Commit 419fbade authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

More rework of VCC-VMOD code.

parent eaa1c903
......@@ -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
......
......@@ -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 = \
......
......@@ -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;
......
......@@ -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);
}
/*-
* Copyright (c) 2010-2015 Varnish Software AS
* All rights reserved.
*
* Author: Poul-Henning Kamp <phk@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);
/*-
* Copyright (c) 2010-2015 Varnish Software AS
* All rights reserved.
*
* Author: Poul-Henning Kamp <phk@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);
}
......@@ -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())
......
......@@ -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",
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment