[master] 419fbadef More rework of VCC-VMOD code.

Poul-Henning Kamp phk at FreeBSD.org
Thu Jun 23 08:32:05 UTC 2022


commit 419fbadefa200830e0f5eba5a29c342ab3d22aad
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Jun 23 08:30:25 2022 +0000

    More rework of VCC-VMOD code.

diff --git a/include/vrt.h b/include/vrt.h
index 975149322..c4afdc6b6 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -58,7 +58,7 @@
  * binary/load-time compatible, increment MAJOR version
  *
  * NEXT (2022-09-15)
- *	C-prototypes moved into JSON
+ *	VMOD C-prototypes moved into JSON
  *	VRT_AddVDP() deprecated
  *	VRT_AddVFP() deprecated
  *	VRT_RemoveVDP() deprecated
diff --git a/lib/libvcc/Makefile.am b/lib/libvcc/Makefile.am
index 8731890da..117f38a3c 100644
--- a/lib/libvcc/Makefile.am
+++ b/lib/libvcc/Makefile.am
@@ -30,6 +30,8 @@ libvcc_la_SOURCES = \
 	vcc_utils.c \
 	vcc_var.c \
 	vcc_vmod.c \
+	vcc_vmod.h \
+	vcc_vmod_sym.c \
 	vcc_xref.c
 
 dist_noinst_SCRIPTS = \
diff --git a/lib/libvcc/vcc_compile.h b/lib/libvcc/vcc_compile.h
index 1663ba92d..d697d3381 100644
--- a/lib/libvcc/vcc_compile.h
+++ b/lib/libvcc/vcc_compile.h
@@ -194,6 +194,9 @@ struct symbol {
 
 	const char			*extra;
 
+	/* vcc_vmod.c */
+	const struct vmod_import	*import;
+
 	/* SYM_VAR */
 	const char			*rname;
 	unsigned			r_methods;
diff --git a/lib/libvcc/vcc_vmod.c b/lib/libvcc/vcc_vmod.c
index db79a5aac..a9f169d10 100644
--- a/lib/libvcc/vcc_vmod.c
+++ b/lib/libvcc/vcc_vmod.c
@@ -26,6 +26,9 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * Parse `import`, check metadata and versioning.
+ *
  */
 
 #include "config.h"
@@ -42,22 +45,31 @@
 #include "vmod_abi.h"
 #include "vsb.h"
 
+#include "vcc_vmod.h"
+
 struct vmod_import {
 	unsigned		magic;
 #define VMOD_IMPORT_MAGIC	0x31803a5d
 	void			*hdl;
 	const char		*err;
-	const struct vmod_data	*vmd;
-};
+	char			*path;
 
-struct vmod_obj {
-	unsigned		magic;
-#define VMOD_OBJ_MAGIC		0x349885f8
+	double			vmod_syntax;
 	char			*name;
-	struct type		type[1];
-	VTAILQ_ENTRY(vmod_obj)	list;
+	char			*func_name;
+	char			*file_id;
+
+	struct symbol		*sym;
+	const struct token	*t_mod;
+	struct vjsn		*vj;
+#define STANZA(UU, ll, ss) int n_##ll;
+	STANZA_TBL
+#undef STANZA
 };
 
+typedef void vcc_do_stanza_f(struct vcc *tl, const struct vmod_import *vim,
+    const struct vjsn_val *vv);
+
 static int
 vcc_path_dlopen(void *priv, const char *fn)
 {
@@ -74,178 +86,111 @@ vcc_path_dlopen(void *priv, const char *fn)
 	return (0);
 }
 
-static void vcc_VmodObject(struct vcc *tl, struct symbol *sym);
-static void vcc_VmodSymbols(struct vcc *tl, const struct symbol *sym);
-
-static void
-alias_sym(struct vcc *tl, const struct symbol *psym, const struct vjsn_val *v)
+static const char *
+vcc_ParseJSON(const struct vcc *tl, const char *jsn, struct vmod_import *vim)
 {
-	char *alias = NULL, *func = NULL;
-	struct symbol *sym;
-	struct vsb *buf;
-
-	buf = VSB_new_auto();
-	AN(buf);
-
-	VCC_SymName(buf, psym);
-	VSB_printf(buf, ".%s", v->value);
-	AZ(VSB_finish(buf));
-	REPLACE(alias, VSB_data(buf));
-
-	v = VTAILQ_NEXT(v, list);
-	assert(vjsn_is_string(v));
-
-	VSB_clear(buf);
-	VCC_SymName(buf, psym);
-	VSB_printf(buf, ".%s", v->value);
-	AZ(VSB_finish(buf));
-	REPLACE(func, VSB_data(buf));
-
-	sym = VCC_MkSymAlias(tl, alias, func);
-	AN(sym);
-	assert(sym->kind == SYM_FUNC || sym->kind == SYM_METHOD);
-	VSB_destroy(&buf);
-	free(alias);
-	free(func);
-}
-
-static void
-func_sym(struct vcc *tl, vcc_kind_t kind, const struct symbol *psym,
-    const struct vjsn_val *v)
-{
-	struct symbol *sym;
-	struct vsb *buf;
-
-	if (kind == SYM_ALIAS) {
-		alias_sym(tl, psym, v);
-		return;
+	const struct vjsn_val *vv, *vv2, *vv3;
+	const char *err;
+
+	vim->vj = vjsn_parse(jsn, &err);
+	if (err != NULL)
+		return (err);
+	AN(vim->vj);
+
+	vv = vim->vj->value;
+	if (!vjsn_is_array(vv))
+		return ("Not array[0]");
+
+	vv2 = VTAILQ_FIRST(&vv->children);
+	if (!vjsn_is_array(vv2))
+		return ("Not array[1]");
+	vv3 = VTAILQ_FIRST(&vv2->children);
+	if (!vjsn_is_string(vv3))
+		return ("Not string[2]");
+	if (strcmp(vv3->value, "$VMOD"))
+		return ("Not $VMOD[3]");
+
+	vv3 = VTAILQ_NEXT(vv3, list);
+	assert(vjsn_is_string(vv3));
+	vim->vmod_syntax = strtod(vv3->value, NULL);
+	assert (vim->vmod_syntax == 1.0);
+
+	vv3 = VTAILQ_NEXT(vv3, list);
+	assert(vjsn_is_string(vv3));
+	vim->name = vv3->value;
+
+	vv3 = VTAILQ_NEXT(vv3, list);
+	assert(vjsn_is_string(vv3));
+	vim->func_name = vv3->value;
+
+	vv3 = VTAILQ_NEXT(vv3, list);
+	assert(vjsn_is_string(vv3));
+	vim->file_id = vv3->value;
+
+	if (!vcc_IdIs(vim->t_mod, vim->name)) {
+		VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n",
+		    PF(vim->t_mod));
+		VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
+		VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vim->name);
+		return ("");
 	}
 
-	buf = VSB_new_auto();
-	AN(buf);
-
-	VCC_SymName(buf, psym);
-	VSB_printf(buf, ".%s", v->value);
-	AZ(VSB_finish(buf));
-	sym = VCC_MkSym(tl, VSB_data(buf), SYM_MAIN, kind, VCL_LOW, VCL_HIGH);
-	AN(sym);
-	VSB_destroy(&buf);
-
-	if (kind == SYM_OBJECT) {
-		sym->eval_priv = v;
-		sym->vmod_name = psym->vmod_name;
-		sym->r_methods = VCL_MET_INIT;
-		vcc_VmodObject(tl, sym);
-		vcc_VmodSymbols(tl, sym);
-		return;
+	VTAILQ_FOREACH(vv2, &vv->children, list) {
+		assert (vjsn_is_array(vv2));
+		vv3 = VTAILQ_FIRST(&vv2->children);
+		assert(vjsn_is_string(vv3));
+		assert(vv3->value[0] == '$');
+#define STANZA(UU, ll, ss) \
+    if (!strcmp(vv3->value, "$" #UU)) {vim->n_##ll++; continue;}
+		STANZA_TBL
+#undef STANZA
+		return ("Unknown entry");
 	}
-
-	if (kind == SYM_METHOD)
-		sym->extra = psym->rname;
-
-	v = VTAILQ_NEXT(v, list);
-
-	assert(vjsn_is_array(v));
-	sym->action = vcc_Act_Call;
-	sym->vmod_name = psym->vmod_name;
-	sym->eval = vcc_Eval_SymFunc;
-	sym->eval_priv = v;
-	v = VTAILQ_FIRST(&v->children);
-	assert(vjsn_is_array(v));
-	v = VTAILQ_FIRST(&v->children);
-	assert(vjsn_is_string(v));
-	sym->type = VCC_Type(v->value);
-	AN(sym->type);
-	sym->r_methods = VCL_MET_TASK_ALL;
+	if (vim->n_cproto != 1)
+		return ("Bad cproto stanza(s)");
+	if (vim->n_vmod != 1)
+		return ("Bad vmod stanza(s)");
+	return (NULL);
 }
 
-static void
-vcc_json_always(struct vcc *tl, const struct vjsn *vj, const char *vmod_name)
-{
-	struct inifin *ifp;
-	const struct vjsn_val *vv, *vv2;
-	double vmod_syntax = 0.0;
-	int cproto_seen = 0;
-
-	AN(vj);
-	AN(vmod_name);
-	ifp = NULL;
-
-	VTAILQ_FOREACH(vv, &vj->value->children, list) {
-		assert(vjsn_is_array(vv));
-		vv2 = VTAILQ_FIRST(&vv->children);
-		assert(vjsn_is_string(vv2));
-		if (!strcmp(vv2->value, "$VMOD")) {
-			vmod_syntax =
-			    strtod(VTAILQ_NEXT(vv2, list)->value, NULL);
-			continue;
-		}
-		assert (vmod_syntax == 1.0);
-		if (!strcmp(vv2->value, "$EVENT")) {
-			/* XXX: What about the rest of the events ? */
-			if (ifp == NULL)
-				ifp = New_IniFin(tl);
-			vv2 = VTAILQ_NEXT(vv2, list);
-			VSB_printf(ifp->ini,
-			    "\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
-			    "\t\treturn(1);",
-			    vv2->value, vmod_name);
-			VSB_printf(ifp->fin,
-			    "\t\t(void)%s(ctx, &vmod_priv_%s,\n"
-			    "\t\t\t    VCL_EVENT_DISCARD);",
-			    vv2->value, vmod_name);
-			VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
-			    vv2->value, vmod_name);
-		} else if (!strcmp(vv2->value, "$ALIAS")) {
-		} else if (!strcmp(vv2->value, "$FUNC")) {
-		} else if (!strcmp(vv2->value, "$OBJ")) {
-		} else if (!strcmp(vv2->value, "$CPROTO")) {
-			cproto_seen = 1;
-		} else {
-			VTAILQ_FOREACH(vv2, &vv->children, list)
-				fprintf(stderr, "\tt %s n %s v %s\n",
-				    vv2->type, vv2->name, vv2->value);
-			WRONG("Vmod JSON syntax error");
-		}
-	}
-	if (!cproto_seen)
-		WRONG("Vmod JSON has no CPROTO");
-}
+/*
+ * Load and check the metadata from the objectfile containing the vmod
+ */
 
-static const struct vmod_data *
-vcc_VmodSanity(struct vcc *tl, void *hdl, const struct token *mod, char *fnp)
+static int
+vcc_VmodLoad(const struct vcc *tl, struct vmod_import *vim, char *fnp)
 {
 	char buf[256];
+	static const char *err;
 	const struct vmod_data *vmd;
 
-	bprintf(buf, "Vmod_%.*s_Data", PF(mod));
-	vmd = dlsym(hdl, buf);
+	CHECK_OBJ_NOTNULL(vim, VMOD_IMPORT_MAGIC);
+	bprintf(buf, "Vmod_%.*s_Data", PF(vim->t_mod));
+	vmd = dlsym(vim->hdl, buf);
 	if (vmd == NULL) {
-		VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(vim->t_mod));
 		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
 		VSB_cat(tl->sb, "\t(no Vmod_Data symbol)\n");
-		vcc_ErrWhere(tl, mod);
-		return (NULL);
+		return (-1);
 	}
 	if (vmd->vrt_major == 0 && vmd->vrt_minor == 0 &&
-	    (vmd->abi == NULL || strcmp(vmd->abi, VMOD_ABI_Version) != 0)) {
-		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
+	    (vmd->abi == NULL || strcmp(vmd->abi, VMOD_ABI_Version))) {
+		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
 		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
 		VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
 			   VMOD_ABI_Version, vmd->abi);
-		vcc_ErrWhere(tl, mod);
-		return (NULL);
+		return (-1);
 	}
-	if (vmd->vrt_major != 0 && (vmd->vrt_major != VRT_MAJOR_VERSION ||
+	if (vmd->vrt_major != 0 &&
+	    (vmd->vrt_major != VRT_MAJOR_VERSION ||
 	    vmd->vrt_minor > VRT_MINOR_VERSION)) {
-		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
 		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
 		VSB_printf(tl->sb, "\tVMOD wants ABI version %u.%u\n",
 		    vmd->vrt_major, vmd->vrt_minor);
 		VSB_printf(tl->sb, "\tvarnishd provides ABI version %u.%u\n",
 		    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
-		vcc_ErrWhere(tl, mod);
-		return (NULL);
+		return (-1);
 	}
 	if (vmd->name == NULL ||
 	    vmd->func == NULL ||
@@ -253,131 +198,146 @@ vcc_VmodSanity(struct vcc *tl, void *hdl, const struct token *mod, char *fnp)
 	    vmd->json == NULL ||
 	    vmd->proto != NULL ||
 	    vmd->abi == NULL) {
-		VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(mod));
+		VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(vim->t_mod));
 		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
 		VSB_cat(tl->sb, "\tInconsistent metadata\n");
-		vcc_ErrWhere(tl, mod);
-		return (NULL);
+		return (-1);
 	}
-	if (!vcc_IdIs(mod, vmd->name)) {
-		VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n", PF(mod));
-		VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
-		VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vmd->name);
-		vcc_ErrWhere(tl, mod);
-		return (NULL);
+
+	err = vcc_ParseJSON(tl, vmd->json, vim);
+	AZ(dlclose(vim->hdl));
+	vim->hdl = NULL;
+	if (err != NULL && *err != '\0') {
+		VSB_printf(tl->sb,
+		    "VMOD %.*s: bad metadata\n", PF(vim->t_mod));
+		VSB_printf(tl->sb, "\t(%s)\n", err);
+		VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
 	}
-	return (vmd);
-}
 
-static vcc_kind_t
-vcc_vmod_kind(const char *type)
-{
+	if (err != NULL)
+		return (-1);
 
-#define VMOD_KIND(str, kind)		\
-	do {				\
-		if (!strcmp(str, type))	\
-			return (kind);	\
-	} while (0)
-	VMOD_KIND("$OBJ", SYM_OBJECT);
-	VMOD_KIND("$METHOD", SYM_METHOD);
-	VMOD_KIND("$FUNC", SYM_FUNC);
-	VMOD_KIND("$ALIAS", SYM_ALIAS);
-#undef VMOD_KIND
-	return (SYM_NONE);
+	return(0);
 }
 
-static void
-vcc_VmodObject(struct vcc *tl, struct symbol *sym)
+static void v_matchproto_(vcc_do_stanza_f)
+vcc_do_event(struct vcc *tl, const struct vmod_import *vim,
+    const struct vjsn_val *vv)
 {
-	struct vmod_obj *obj;
-	struct vsb *buf;
-
-	buf = VSB_new_auto();
-	AN(buf);
-
-	VSB_printf(buf, "%s.%s", sym->vmod_name, sym->name);
-	AZ(VSB_finish(buf));
-
-	ALLOC_OBJ(obj, VMOD_OBJ_MAGIC);
-	AN(obj);
-	REPLACE(obj->name, VSB_data(buf));
+	struct inifin *ifp;
 
-	INIT_OBJ(obj->type, TYPE_MAGIC);
-	obj->type->name = obj->name;
-	sym->type = obj->type;
-	VTAILQ_INSERT_TAIL(&tl->vmod_objects, obj, list);
-	VSB_destroy(&buf);
+	ifp = New_IniFin(tl);
+	VSB_printf(ifp->ini,
+	    "\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
+	    "\t\treturn(1);",
+	    vv->value, vim->sym->vmod_name);
+	VSB_printf(ifp->fin,
+	    "\t\t(void)%s(ctx, &vmod_priv_%s,\n"
+	    "\t\t\t    VCL_EVENT_DISCARD);",
+	    vv->value, vim->sym->vmod_name);
+	VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
+	    vv->value, vim->sym->vmod_name);
 }
 
-static void
-vcc_VmodSymbols(struct vcc *tl, const struct symbol *sym)
+static void v_matchproto_(vcc_do_stanza_f)
+vcc_do_cproto(struct vcc *tl, const struct vmod_import *vim,
+    const struct vjsn_val *vv)
 {
-	const struct vjsn *vj;
-	const struct vjsn_val *vv, *vv1, *vv2;
-	vcc_kind_t kind;
-
-	if (sym->kind == SYM_VMOD) {
-		CAST_OBJ_NOTNULL(vj, sym->eval_priv, VJSN_MAGIC);
-		vv = VTAILQ_FIRST(&vj->value->children);
-	} else if (sym->kind == SYM_OBJECT) {
-		CAST_OBJ_NOTNULL(vv, sym->eval_priv, VJSN_VAL_MAGIC);
-	} else {
-		WRONG("symbol kind");
-	}
-
-	for (; vv != NULL; vv = VTAILQ_NEXT(vv, list)) {
-		if (!vjsn_is_array(vv))
-			continue;
-		vv1 = VTAILQ_FIRST(&vv->children);
-		assert(vjsn_is_string(vv1));
-		vv2 = VTAILQ_NEXT(vv1, list);
-		if (!vjsn_is_string(vv2))
-			continue;
-
-		kind = vcc_vmod_kind(vv1->value);
-		if (kind == SYM_NONE)
-			continue;
-
-		func_sym(tl, kind, sym, vv2);
-	}
+	(void)vim;
+	do {
+		assert (vjsn_is_string(vv));
+		Fh(tl, 0, "%s\n", vv->value);
+		vv = VTAILQ_NEXT(vv, list);
+	} while(vv != NULL);
 }
 
 static void
-vcc_emit_c_prototypes(const struct vcc *tl, const struct vjsn *vj)
+vcc_vj_foreach(struct vcc *tl, const struct vmod_import *vim,
+    const char *stanza, vcc_do_stanza_f *func)
 {
 	const struct vjsn_val *vv, *vv2, *vv3;
 
-	Fh(tl, 0, "\n");
-	vv = vj->value;
+	vv = vim->vj->value;
 	assert (vjsn_is_array(vv));
-	vv3 = NULL;
 	VTAILQ_FOREACH(vv2, &vv->children, list) {
 		assert (vjsn_is_array(vv2));
 		vv3 = VTAILQ_FIRST(&vv2->children);
 		assert (vjsn_is_string(vv3));
-		if (!strcmp(vv3->value, "$CPROTO"))
-			break;
-	}
-	assert(vv3 != NULL);
-	while (1) {
-		vv3 = VTAILQ_NEXT(vv3, list);
-		if (vv3 == NULL)
-			break;
-		assert (vjsn_is_string(vv3));
-		Fh(tl, 0, "%s\n", vv3->value);
+		if (!strcmp(vv3->value, stanza))
+			func(tl, vim, VTAILQ_NEXT(vv3, list));
 	}
 }
 
+static void
+vcc_emit_setup(struct vcc *tl, const struct vmod_import *vim)
+{
+	struct inifin *ifp;
+	const struct token *mod = vim->t_mod;
+
+	ifp = New_IniFin(tl);
+
+	VSB_cat(ifp->ini, "\tif (VPI_Vmod_Init(ctx,\n");
+	VSB_printf(ifp->ini, "\t    &VGC_vmod_%.*s,\n", PF(mod));
+	VSB_printf(ifp->ini, "\t    %u,\n", tl->vmod_count++);
+	VSB_printf(ifp->ini, "\t    &%s,\n", vim->func_name);
+	VSB_printf(ifp->ini, "\t    sizeof(%s),\n", vim->func_name);
+	VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
+	VSB_cat(ifp->ini, "\t    ");
+	VSB_quote(ifp->ini, vim->path, -1, VSB_QUOTE_CSTR);
+	VSB_cat(ifp->ini, ",\n");
+	AN(vim->file_id);
+	VSB_printf(ifp->ini, "\t    \"%s\",\n", vim->file_id);
+	VSB_printf(ifp->ini, "\t    \"./vmod_cache/_vmod_%.*s.%s\"\n",
+	    PF(mod), vim->file_id);
+	VSB_cat(ifp->ini, "\t    ))\n");
+	VSB_cat(ifp->ini, "\t\treturn(1);");
+
+	VSB_cat(tl->symtab, ",\n    {\n");
+	VSB_cat(tl->symtab, "\t\"dir\": \"import\",\n");
+	VSB_cat(tl->symtab, "\t\"type\": \"$VMOD\",\n");
+	VSB_printf(tl->symtab, "\t\"name\": \"%.*s\",\n", PF(mod));
+	VSB_printf(tl->symtab, "\t\"file\": \"%s\",\n", vim->path);
+	VSB_printf(tl->symtab, "\t\"dst\": \"./vmod_cache/_vmod_%.*s.%s\"\n",
+	    PF(mod), vim->file_id);
+	VSB_cat(tl->symtab, "    }");
+
+	/* XXX: zero the function pointer structure ?*/
+	VSB_printf(ifp->fin, "\t\tVRT_priv_fini(ctx, &vmod_priv_%.*s);",
+	    PF(mod));
+	VSB_printf(ifp->final, "\t\tVPI_Vmod_Unload(ctx, &VGC_vmod_%.*s);",
+	    PF(mod));
+
+	vcc_vj_foreach(tl, vim, "$EVENT", vcc_do_event);
+
+	Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
+	Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
+	Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
+
+	vcc_vj_foreach(tl, vim, "$CPROTO", vcc_do_cproto);
+
+	Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
+}
+
+static void
+vcc_vim_destroy(struct vmod_import **vimp)
+{
+	struct vmod_import *vim;
+
+	TAKE_OBJ_NOTNULL(vim, vimp, VMOD_IMPORT_MAGIC);
+	if (vim->path)
+		free(vim->path);
+	if (vim->vj)
+		vjsn_delete(&vim->vj);
+	FREE_OBJ(vim);
+}
+
 void
 vcc_ParseImport(struct vcc *tl)
 {
-	char fn[1024], *fnpx;
+	char fn[1024];
 	const char *p;
 	struct token *mod, *tmod, *t1;
-	struct inifin *ifp;
 	struct symbol *msym, *vsym;
-	const struct vmod_data *vmd;
-	struct vjsn *vj;
 	struct vmod_import *vim;
 	const struct vmod_import *vimold;
 
@@ -428,8 +388,10 @@ vcc_ParseImport(struct vcc *tl)
 
 	ALLOC_OBJ(vim, VMOD_IMPORT_MAGIC);
 	AN(vim);
+	vim->t_mod = mod;
+	vim->sym = msym;
 
-	if (VFIL_searchpath(tl->vmod_path, vcc_path_dlopen, vim, fn, &fnpx)) {
+	if (VFIL_searchpath(tl->vmod_path, vcc_path_dlopen, vim, fn, &vim->path)) {
 		if (vim->err == NULL) {
 			VSB_printf(tl->sb,
 			    "Could not find VMOD %.*s\n", PF(mod));
@@ -437,26 +399,24 @@ vcc_ParseImport(struct vcc *tl)
 			VSB_printf(tl->sb,
 			    "Could not open VMOD %.*s\n", PF(mod));
 			VSB_printf(tl->sb, "\tFile name: %s\n",
-			    fnpx != NULL ? fnpx : fn);
+			    vim->path != NULL ? vim->path : fn);
 			VSB_printf(tl->sb, "\tdlerror: %s\n", vim->err);
 		}
 		vcc_ErrWhere(tl, mod);
-		free(fnpx);
-		FREE_OBJ(vim);
+		vcc_vim_destroy(&vim);
 		return;
 	}
 
-	vmd = vcc_VmodSanity(tl, vim->hdl, mod, fnpx);
-	if (vmd == NULL || tl->err) {
-		AZ(dlclose(vim->hdl));
-		free(fnpx);
-		FREE_OBJ(vim);
+	if (vcc_VmodLoad(tl, vim, vim->path) < 0 || tl->err) {
+		vcc_ErrWhere(tl, vim->t_mod);
+		vcc_vim_destroy(&vim);
 		return;
 	}
 
-	CAST_OBJ(vimold, (const void*)(msym->extra), VMOD_IMPORT_MAGIC);
+	vimold = msym->import;
 	if (vimold != NULL) {
-		if (!strcmp(vimold->vmd->file_id, vmd->file_id)) {
+		CHECK_OBJ_NOTNULL(vimold, VMOD_IMPORT_MAGIC);
+		if (!strcmp(vimold->file_id, vim->file_id)) {
 			/* Identical import is OK */
 		} else {
 			VSB_printf(tl->sb,
@@ -464,9 +424,7 @@ vcc_ParseImport(struct vcc *tl)
 			    PF(tmod));
 			vcc_ErrWhere2(tl, t1, tl->t);
 		}
-		AZ(dlclose(vim->hdl));
-		free(fnpx);
-		FREE_OBJ(vim);
+		vcc_vim_destroy(&vim);
 		return;
 	}
 	msym->def_b = t1;
@@ -474,151 +432,26 @@ vcc_ParseImport(struct vcc *tl)
 
 	VTAILQ_FOREACH(vsym, &tl->sym_vmods, sideways) {
 		assert(vsym->kind == SYM_VMOD);
-		CAST_OBJ_NOTNULL(vimold, (const void*)(vsym->extra),
-		    VMOD_IMPORT_MAGIC);
-		if (!strcmp(vimold->vmd->file_id, vmd->file_id)) {
+		vimold = vsym->import;
+		CHECK_OBJ_NOTNULL(vimold, VMOD_IMPORT_MAGIC);
+		if (!strcmp(vimold->file_id, vim->file_id)) {
 			/* Already loaded under different name */
 			msym->eval_priv = vsym->eval_priv;
-			msym->extra = vsym->extra;
+			msym->import = vsym->import;
 			msym->vmod_name = vsym->vmod_name;
 			vcc_VmodSymbols(tl, msym);
-			AZ(dlclose(vim->hdl));
-			free(fnpx);
-			FREE_OBJ(vim);
+			// XXX: insert msym in sideways ?
+			vcc_vim_destroy(&vim);
 			return;
 		}
 	}
 
 	VTAILQ_INSERT_TAIL(&tl->sym_vmods, msym, sideways);
 
-	ifp = New_IniFin(tl);
-
-	VSB_cat(ifp->ini, "\tif (VPI_Vmod_Init(ctx,\n");
-	VSB_printf(ifp->ini, "\t    &VGC_vmod_%.*s,\n", PF(mod));
-	VSB_printf(ifp->ini, "\t    %u,\n", tl->vmod_count++);
-	VSB_printf(ifp->ini, "\t    &%s,\n", vmd->func_name);
-	VSB_printf(ifp->ini, "\t    sizeof(%s),\n", vmd->func_name);
-	VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
-	VSB_cat(ifp->ini, "\t    ");
-	VSB_quote(ifp->ini, fnpx, -1, VSB_QUOTE_CSTR);
-	VSB_cat(ifp->ini, ",\n");
-	AN(vmd);
-	AN(vmd->file_id);
-	VSB_printf(ifp->ini, "\t    \"%s\",\n", vmd->file_id);
-	VSB_printf(ifp->ini, "\t    \"./vmod_cache/_vmod_%.*s.%s\"\n",
-	    PF(mod), vmd->file_id);
-	VSB_cat(ifp->ini, "\t    ))\n");
-	VSB_cat(ifp->ini, "\t\treturn(1);");
-
-	VSB_cat(tl->symtab, ",\n    {\n");
-	VSB_cat(tl->symtab, "\t\"dir\": \"import\",\n");
-	VSB_cat(tl->symtab, "\t\"type\": \"$VMOD\",\n");
-	VSB_printf(tl->symtab, "\t\"name\": \"%.*s\",\n", PF(mod));
-	VSB_printf(tl->symtab, "\t\"file\": \"%s\",\n", fnpx);
-	VSB_printf(tl->symtab, "\t\"dst\": \"./vmod_cache/_vmod_%.*s.%s\"\n",
-	    PF(mod), vmd->file_id);
-	VSB_cat(tl->symtab, "    }");
-
-	/* XXX: zero the function pointer structure ?*/
-	VSB_printf(ifp->fin, "\t\tVRT_priv_fini(ctx, &vmod_priv_%.*s);", PF(mod));
-	VSB_printf(ifp->final, "\t\tVPI_Vmod_Unload(ctx, &VGC_vmod_%.*s);", PF(mod));
-
-	vj = vjsn_parse(vmd->json, &p);
-	XXXAZ(p);
-	AN(vj);
-	msym->eval_priv = vj;
-	vim->vmd = vmd;
-	msym->extra = (const char *)vim;
-	msym->vmod_name = TlDup(tl, vmd->name);
+	msym->eval_priv = vim->vj;
+	msym->import = vim;
+	msym->vmod_name = TlDup(tl, vim->name);
 	vcc_VmodSymbols(tl, msym);
 
-	vcc_json_always(tl, vj, msym->vmod_name);
-
-	Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
-	Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
-	Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
-	vcc_emit_c_prototypes(tl, vj);
-	Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
-	free(fnpx);
-}
-
-void v_matchproto_(sym_act_f)
-vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
-{
-	struct symbol *isym, *osym;
-	struct inifin *ifp;
-	struct vsb *buf;
-	const struct vjsn_val *vv, *vf;
-	int null_ok = 0;
-
-	(void)sym;
-	(void)t;
-
-	ExpectErr(tl, ID);
-	vcc_ExpectVid(tl, "VCL object");
-	ERRCHK(tl);
-	isym = VCC_HandleSymbol(tl, INSTANCE);
-	ERRCHK(tl);
-	AN(isym);
-	isym->noref = 1;
-	isym->action = vcc_Act_Obj;
-
-	SkipToken(tl, '=');
-	ExpectErr(tl, ID);
-	osym = VCC_SymbolGet(tl, SYM_MAIN, SYM_OBJECT, SYMTAB_EXISTING,
-	    XREF_NONE);
-	ERRCHK(tl);
-	AN(osym);
-
-	/* Scratch the generic INSTANCE type */
-	isym->type = osym->type;
-
-	CAST_OBJ_NOTNULL(vv, osym->eval_priv, VJSN_VAL_MAGIC);
-	// vv = object name
-
-	isym->vmod_name = osym->vmod_name;
-	isym->eval_priv = vv;
-
-	vv = VTAILQ_NEXT(vv, list);
-	// vv = flags
-	assert(vjsn_is_object(vv));
-	VTAILQ_FOREACH(vf, &vv->children, list)
-		if (!strcmp(vf->name, "NULL_OK") && vjsn_is_true(vf))
-			null_ok = 1;
-	if (!null_ok)
-		VTAILQ_INSERT_TAIL(&tl->sym_objects, isym, sideways);
-
-	vv = VTAILQ_NEXT(vv, list);
-	// vv = struct name
-
-	Fh(tl, 0, "static %s *%s;\n\n", vv->value, isym->rname);
-	vv = VTAILQ_NEXT(vv, list);
-
-	vf = VTAILQ_FIRST(&vv->children);
-	vv = VTAILQ_NEXT(vv, list);
-	assert(vjsn_is_string(vf));
-	assert(!strcmp(vf->value, "$INIT"));
-
-	vf = VTAILQ_NEXT(vf, list);
-
-	buf = VSB_new_auto();
-	AN(buf);
-	VSB_printf(buf, "&%s, \"%s\"", isym->rname, isym->name);
-	AZ(VSB_finish(buf));
-	vcc_Eval_Func(tl, vf, VSB_data(buf), osym);
-	VSB_destroy(&buf);
-	ERRCHK(tl);
-	SkipToken(tl, ';');
-	isym->def_e = tl->t;
-
-	vf = VTAILQ_FIRST(&vv->children);
-	assert(vjsn_is_string(vf));
-	assert(!strcmp(vf->value, "$FINI"));
-
-	vf = VTAILQ_NEXT(vf, list);
-	vf = VTAILQ_FIRST(&vf->children);
-	vf = VTAILQ_NEXT(vf, list);
-	ifp = New_IniFin(tl);
-	VSB_printf(ifp->fin, "\t\tif (%s)\n", isym->rname);
-	VSB_printf(ifp->fin, "\t\t\t\t%s(&%s);", vf->value, isym->rname);
+	vcc_emit_setup(tl, vim);
 }
diff --git a/lib/libvcc/vcc_vmod.h b/lib/libvcc/vcc_vmod.h
new file mode 100644
index 000000000..2f386cf5a
--- /dev/null
+++ b/lib/libvcc/vcc_vmod.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2010-2015 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define STANZA_TBL \
+	STANZA(ALIAS, alias, SYM_ALIAS) \
+	STANZA(CPROTO, cproto, SYM_NONE) \
+	STANZA(EVENT, evant, SYM_NONE) \
+	STANZA(FUNC, func, SYM_FUNC) \
+	STANZA(METHOD, method, SYM_METHOD) \
+	STANZA(OBJ, obj, SYM_OBJECT) \
+	STANZA(VMOD, vmod, SYM_NONE)
+
+void vcc_VmodSymbols(struct vcc *tl, const struct symbol *sym);
diff --git a/lib/libvcc/vcc_vmod_sym.c b/lib/libvcc/vcc_vmod_sym.c
new file mode 100644
index 000000000..65f7f4d6f
--- /dev/null
+++ b/lib/libvcc/vcc_vmod_sym.c
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 2010-2015 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Turn vmod JSON spec into symbols
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vcc_compile.h"
+
+#include "libvcc.h"
+#include "vjsn.h"
+#include "vsb.h"
+
+#include "vcc_vmod.h"
+
+struct vmod_obj {
+	unsigned		magic;
+#define VMOD_OBJ_MAGIC		0x349885f8
+	char			*name;
+	struct type		type[1];
+	VTAILQ_ENTRY(vmod_obj)	list;
+};
+
+static void
+vcc_VmodObject(struct vcc *tl, struct symbol *sym)
+{
+	struct vmod_obj *obj;
+	struct vsb *buf;
+
+	buf = VSB_new_auto();
+	AN(buf);
+
+	VSB_printf(buf, "%s.%s", sym->vmod_name, sym->name);
+	AZ(VSB_finish(buf));
+
+	ALLOC_OBJ(obj, VMOD_OBJ_MAGIC);
+	AN(obj);
+	REPLACE(obj->name, VSB_data(buf));
+
+	INIT_OBJ(obj->type, TYPE_MAGIC);
+	obj->type->name = obj->name;
+	sym->type = obj->type;
+	VTAILQ_INSERT_TAIL(&tl->vmod_objects, obj, list);
+	VSB_destroy(&buf);
+}
+
+static void
+alias_sym(struct vcc *tl, const struct symbol *psym, const struct vjsn_val *v)
+{
+	char *alias = NULL, *func = NULL;
+	struct symbol *sym;
+	struct vsb *buf;
+
+	buf = VSB_new_auto();
+	AN(buf);
+
+	VCC_SymName(buf, psym);
+	VSB_printf(buf, ".%s", v->value);
+	AZ(VSB_finish(buf));
+	REPLACE(alias, VSB_data(buf));
+
+	v = VTAILQ_NEXT(v, list);
+	assert(vjsn_is_string(v));
+
+	VSB_clear(buf);
+	VCC_SymName(buf, psym);
+	VSB_printf(buf, ".%s", v->value);
+	AZ(VSB_finish(buf));
+	REPLACE(func, VSB_data(buf));
+
+	sym = VCC_MkSymAlias(tl, alias, func);
+	AN(sym);
+	assert(sym->kind == SYM_FUNC || sym->kind == SYM_METHOD);
+	VSB_destroy(&buf);
+	free(alias);
+	free(func);
+}
+
+static void
+func_sym(struct vcc *tl, vcc_kind_t kind, const struct symbol *psym,
+    const struct vjsn_val *v)
+{
+	struct symbol *sym;
+	struct vsb *buf;
+
+	if (kind == SYM_ALIAS) {
+		alias_sym(tl, psym, v);
+		return;
+	}
+
+	buf = VSB_new_auto();
+	AN(buf);
+
+	VCC_SymName(buf, psym);
+	VSB_printf(buf, ".%s", v->value);
+	AZ(VSB_finish(buf));
+	sym = VCC_MkSym(tl, VSB_data(buf), SYM_MAIN, kind, VCL_LOW, VCL_HIGH);
+	AN(sym);
+	VSB_destroy(&buf);
+
+	if (kind == SYM_OBJECT) {
+		sym->eval_priv = v;
+		sym->vmod_name = psym->vmod_name;
+		sym->r_methods = VCL_MET_INIT;
+		vcc_VmodObject(tl, sym);
+		vcc_VmodSymbols(tl, sym);
+		return;
+	}
+
+	if (kind == SYM_METHOD)
+		sym->extra = psym->rname;
+
+	v = VTAILQ_NEXT(v, list);
+
+	assert(vjsn_is_array(v));
+	sym->action = vcc_Act_Call;
+	sym->vmod_name = psym->vmod_name;
+	sym->eval = vcc_Eval_SymFunc;
+	sym->eval_priv = v;
+	v = VTAILQ_FIRST(&v->children);
+	assert(vjsn_is_array(v));
+	v = VTAILQ_FIRST(&v->children);
+	assert(vjsn_is_string(v));
+	sym->type = VCC_Type(v->value);
+	AN(sym->type);
+	sym->r_methods = VCL_MET_TASK_ALL;
+}
+
+void
+vcc_VmodSymbols(struct vcc *tl, const struct symbol *sym)
+{
+	const struct vjsn *vj;
+	const struct vjsn_val *vv, *vv1, *vv2;
+	vcc_kind_t kind;
+
+	if (sym->kind == SYM_VMOD) {
+		CAST_OBJ_NOTNULL(vj, sym->eval_priv, VJSN_MAGIC);
+		vv = VTAILQ_FIRST(&vj->value->children);
+	} else if (sym->kind == SYM_OBJECT) {
+		CAST_OBJ_NOTNULL(vv, sym->eval_priv, VJSN_VAL_MAGIC);
+	} else {
+		WRONG("symbol kind");
+	}
+
+	for (; vv != NULL; vv = VTAILQ_NEXT(vv, list)) {
+		if (!vjsn_is_array(vv))
+			continue;
+		vv1 = VTAILQ_FIRST(&vv->children);
+		assert(vjsn_is_string(vv1));
+		vv2 = VTAILQ_NEXT(vv1, list);
+		if (!vjsn_is_string(vv2))
+			continue;
+
+		kind = SYM_NONE;
+#define STANZA(UU, ll, ss) if (!strcmp(vv1->value, "$" #UU)) kind = ss;
+	STANZA_TBL
+#undef STANZA
+		if (kind != SYM_NONE)
+			func_sym(tl, kind, sym, vv2);
+	}
+}
+
+void v_matchproto_(sym_act_f)
+vcc_Act_New(struct vcc *tl, struct token *t, struct symbol *sym)
+{
+	struct symbol *isym, *osym;
+	struct inifin *ifp;
+	struct vsb *buf;
+	const struct vjsn_val *vv, *vf;
+	int null_ok = 0;
+
+	(void)sym;
+	(void)t;
+
+	ExpectErr(tl, ID);
+	vcc_ExpectVid(tl, "VCL object");
+	ERRCHK(tl);
+	isym = VCC_HandleSymbol(tl, INSTANCE);
+	ERRCHK(tl);
+	AN(isym);
+	isym->noref = 1;
+	isym->action = vcc_Act_Obj;
+
+	SkipToken(tl, '=');
+	ExpectErr(tl, ID);
+	osym = VCC_SymbolGet(tl, SYM_MAIN, SYM_OBJECT, SYMTAB_EXISTING,
+	    XREF_NONE);
+	ERRCHK(tl);
+	AN(osym);
+
+	/* Scratch the generic INSTANCE type */
+	isym->type = osym->type;
+
+	CAST_OBJ_NOTNULL(vv, osym->eval_priv, VJSN_VAL_MAGIC);
+	// vv = object name
+
+	isym->vmod_name = osym->vmod_name;
+	isym->eval_priv = vv;
+
+	vv = VTAILQ_NEXT(vv, list);
+	// vv = flags
+	assert(vjsn_is_object(vv));
+	VTAILQ_FOREACH(vf, &vv->children, list)
+		if (!strcmp(vf->name, "NULL_OK") && vjsn_is_true(vf))
+			null_ok = 1;
+	if (!null_ok)
+		VTAILQ_INSERT_TAIL(&tl->sym_objects, isym, sideways);
+
+	vv = VTAILQ_NEXT(vv, list);
+	// vv = struct name
+
+	Fh(tl, 0, "static %s *%s;\n\n", vv->value, isym->rname);
+	vv = VTAILQ_NEXT(vv, list);
+
+	vf = VTAILQ_FIRST(&vv->children);
+	vv = VTAILQ_NEXT(vv, list);
+	assert(vjsn_is_string(vf));
+	assert(!strcmp(vf->value, "$INIT"));
+
+	vf = VTAILQ_NEXT(vf, list);
+
+	buf = VSB_new_auto();
+	AN(buf);
+	VSB_printf(buf, "&%s, \"%s\"", isym->rname, isym->name);
+	AZ(VSB_finish(buf));
+	vcc_Eval_Func(tl, vf, VSB_data(buf), osym);
+	VSB_destroy(&buf);
+	ERRCHK(tl);
+	SkipToken(tl, ';');
+	isym->def_e = tl->t;
+
+	vf = VTAILQ_FIRST(&vv->children);
+	assert(vjsn_is_string(vf));
+	assert(!strcmp(vf->value, "$FINI"));
+
+	vf = VTAILQ_NEXT(vf, list);
+	vf = VTAILQ_FIRST(&vf->children);
+	vf = VTAILQ_NEXT(vf, list);
+	ifp = New_IniFin(tl);
+	VSB_printf(ifp->fin, "\t\tif (%s)\n", isym->rname);
+	VSB_printf(ifp->fin, "\t\t\t\t%s(&%s);", vf->value, isym->rname);
+}
diff --git a/lib/libvcc/vmodtool.py b/lib/libvcc/vmodtool.py
index 823e12385..1ea7f66be 100755
--- a/lib/libvcc/vmodtool.py
+++ b/lib/libvcc/vmodtool.py
@@ -1086,7 +1086,7 @@ class vcc(object):
 
     def iter_json(self, fnx):
 
-        jl = [["$VMOD", "1.0"]]
+        jl = [["$VMOD", "1.0", self.modname, self.csn, self.file_id]]
         jl.append(["$CPROTO"])
         for i in open(fnx):
             jl[-1].append(i.rstrip())
diff --git a/vmod/vmod_debug.c b/vmod/vmod_debug.c
index 53b0ebc14..a0a11f5b6 100644
--- a/vmod/vmod_debug.c
+++ b/vmod/vmod_debug.c
@@ -1087,7 +1087,15 @@ const struct vmod_data Vmod_wrong2_Data = {
 	.func =		foo_struct,
 	.func_len =	sizeof foo_struct,
 	.func_name =	"foo_struct",
-	.json =		"blablabla",
+	.json =		"["
+			    "["
+				"\"$VMOD\""
+				", \"1.0\""
+				", \"wrongN\""
+				", \"foo_struct\""
+				", \"file_id\""
+			    "]"
+			"]",
 };
 
 extern const struct vmod_data Vmod_wrong3_Data;
@@ -1098,7 +1106,16 @@ const struct vmod_data Vmod_wrong3_Data = {
 	.func =		foo_struct,
 	.func_len =	sizeof foo_struct,
 	.func_name =	"foo_struct",
-	.json =		"blablabla",
+	.json =		"["
+			    "["
+				"\"$VMOD\""
+				", \"1.0\""
+				", \"wrongN\""
+				", \"foo_struct\""
+				", \"file_id\""
+			    "]"
+			    ", [\"$CPROTO\", \"\"]"
+			"]",
 	.abi =		"abiblabla",
 };
 


More information about the varnish-commit mailing list