varnish-cache/lib/libvcc/vcc_xref.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9 50
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15 50
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 50
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 50
 * SUCH DAMAGE.
29
 *
30
 * This file contains code for two cross-reference or consistency checks.
31
 *
32
 * The first check is simply that all subroutine, acls and backends are
33 29275
 * both defined and referenced.  Complaints about referenced but undefined
34 29275
 * or defined but unreferenced objects will be emitted.
35
 *
36
 * The second check recursively decends through subroutine calls to make
37
 * sure that action actions are correct for the methods through which
38
 * they are called.
39
 */
40
41
#include "config.h"
42
43
#include <string.h>
44 50
#include "vcc_compile.h"
45
46
/*--------------------------------------------------------------------*/
47
48
struct proccall {
49
        VTAILQ_ENTRY(proccall)  list;
50 50
        struct symbol           *sym;
51
        struct token            *t;
52
        struct proc             *fm;
53
};
54 50
55
struct procuse {
56
        VTAILQ_ENTRY(procuse)   list;
57
        const struct token      *t1;
58 50
        const struct token      *t2;
59
        const struct symbol     *sym;
60
        const struct xrefuse    *use;
61
        unsigned                mask;
62
        struct proc             *fm;
63 50
};
64
65
struct procpriv {
66
        VTAILQ_ENTRY(procpriv)  list;
67
        const char              *vmod;
68
};
69
70 50
/*--------------------------------------------------------------------*/
71
72
static void
73 13232275
vcc_checkref(struct vcc *tl, const struct symbol *sym)
74
{
75 50
76 13232275
        if (sym->noref)
77 11804400
                return;
78 1427875
        if (sym->ndef == 0 && sym->nref != 0) {
79 125
                AN(sym->ref_b);
80 150
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
81 75
                    sym->kind->name, PF(sym->ref_b));
82 75
                vcc_ErrWhere(tl, sym->ref_b);
83 1427875
        } else if (sym->ndef != 0 && sym->nref == 0) {
84 3175
                AN(sym->def_b);
85 6350
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
86 3175
                    sym->kind->name, PF(sym->def_b));
87 3175
                vcc_ErrWhere(tl, sym->def_b);
88 3175
                if (!tl->err_unref)
89 3075
                        vcc_Warn(tl);
90 3175
        }
91 13232275
}
92
93
int
94 67225
vcc_CheckReferences(struct vcc *tl)
95
{
96
97 67175
        VCC_WalkSymbols(tl, vcc_checkref, SYM_MAIN, SYM_NONE);
98 67175
        return (tl->err);
99
}
100
101
/*--------------------------------------------------------------------
102
 * Returns checks
103
 */
104 50
105
const struct xrefuse XREF_READ[1] = {{"xref_read", "Not available"}};
106
const struct xrefuse XREF_WRITE[1] = {{"xref_write", "Cannot be set"}};
107
const struct xrefuse XREF_UNSET[1] = {{"xref_unset", "Cannot be unset"}};
108
const struct xrefuse XREF_ACTION[1] = {{"xref_action", "Not a valid action"}};
109
110
void
111 3887100
vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
112
    const struct symbol *sym, const struct xrefuse *use)
113
{
114
        struct procuse *pu;
115
116 3887100
        AN(tl->curproc);
117 3887100
        pu = TlAlloc(tl, sizeof *pu);
118 3887100
        AN(pu);
119 3887100
        AN(sym);
120 3887100
        AN(use);
121 3887100
        AN(use->name);
122 3887100
        pu->t1 = t1;
123 3887100
        pu->t2 = t2;
124 3887100
        if (pu->t2 == NULL) {
125 3147650
                pu->t2 = vcc_PeekTokenFrom(tl, t1);
126 3147650
                AN(pu->t2);
127 3147650
        }
128 3887100
        pu->sym = sym;
129 3887100
        pu->use = use;
130 3887100
        pu->fm = tl->curproc;
131
132 3887100
        if (pu->use == XREF_READ)
133 2940525
                pu->mask = sym->r_methods;
134 946575
        else if (pu->use == XREF_WRITE)
135 671100
                pu->mask = sym->w_methods;
136 275475
        else if (pu->use == XREF_UNSET)
137 68350
                pu->mask = sym->u_methods;
138 207125
        else if (pu->use == XREF_ACTION)
139 207125
                pu->mask = sym->action_mask;
140
        else
141 0
                WRONG("wrong xref use");
142
143 3887100
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
144 3887100
}
145
146
void
147 1615575
vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym)
148
{
149
        struct proccall *pc;
150
151 1615575
        AN(sym);
152 1615575
        pc = TlAlloc(tl, sizeof *pc);
153 1615575
        AN(pc);
154 1615575
        pc->sym = sym;
155 1615575
        pc->t = t;
156 1615575
        pc->fm = tl->curproc;
157 1615575
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
158 1615575
}
159
160
void
161 1492050
vcc_ProcAction(struct proc *p, unsigned returns, unsigned mask, struct token *t)
162
{
163
164 1492050
        assert(returns < VCL_RET_MAX);
165 1492050
        p->ret_bitmap |= (1U << returns);
166 1492050
        p->okmask &= mask;
167
        /* Record the first instance of this return */
168 1492050
        if (p->return_tok[returns] == NULL)
169 1488000
                p->return_tok[returns] = t;
170 1492050
}
171
172
static int
173 5022900
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
174
{
175
        unsigned u;
176
        struct proccall *pc;
177
178 5022900
        AN(p);
179 5022900
        if (p->active) {
180 50
                VSB_cat(tl->sb, "Subroutine recurses on\n");
181 50
                vcc_ErrWhere(tl, p->name);
182 50
                return (1);
183
        }
184 5022850
        u = p->ret_bitmap & ~bitmap;
185 5022850
        if (u) {
186
187
#define VCL_RET_MAC(l, U, B)                                            \
188
                if (u & (1 << (VCL_RET_##U))) {                         \
189
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
190
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
191
                }
192
#include "tbl/vcl_returns.h"
193
194 50
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
195 25
                    PF(p->name));
196 25
                vcc_ErrWhere(tl, p->name);
197 25
                return (1);
198
        }
199
200
        // more references than calls -> sub is referenced for dynamic calls
201 5022825
        u = (p->sym->nref > p->called);
202
203 5022825
        p->active = 1;
204 7702550
        VTAILQ_FOREACH(pc, &p->calls, list) {
205 2679825
                if (pc->sym->proc == NULL) {
206 0
                        VSB_printf(tl->sb, "Subroutine %s does not exist\n",
207 0
                            pc->sym->name);
208 0
                        vcc_ErrWhere(tl, pc->t);
209 0
                        return (1);
210
                }
211 2679825
                pc->sym->proc->calledfrom |= p->calledfrom;
212 2679825
                pc->sym->proc->called++;
213 2679825
                pc->sym->nref += u;
214 2679825
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
215 200
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
216 100
                            PF(p->name));
217 100
                        vcc_ErrWhere(tl, pc->t);
218 100
                        return (1);
219
                }
220 2679725
                p->okmask &= pc->sym->proc->okmask;
221 2679725
        }
222 5022725
        p->active = 0;
223 5022725
        return (0);
224 5022900
}
225
226
/*--------------------------------------------------------------------*/
227
228
static void
229 2343075
vcc_checkaction(struct vcc *tl, const struct symbol *sym)
230
{
231
        struct proc *p;
232
        unsigned bitmap;
233
234 2343075
        p = sym->proc;
235 2343075
        AN(p);
236 2343075
        AN(p->name);
237
238 2343075
        if (p->method == NULL) {
239 1406500
                bitmap = ~0U;
240 1406500
        } else {
241 936575
                bitmap = p->method->ret_bitmap;
242 936575
                p->calledfrom = p->method->bitval;
243
        }
244
245 2343075
        if (! vcc_CheckActionRecurse(tl, p, bitmap))
246 2343000
                return;
247
248 75
        tl->err = 1;
249 75
        if (p->method == NULL)
250 50
                return;
251
252 50
        VSB_printf(tl->sb,
253 25
                   "\n...which is the \"%s\" subroutine\n", p->method->name);
254 25
        VSB_cat(tl->sb, "Legal returns are:");
255
#define VCL_RET_MAC(l, U, B)                                            \
256
        if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))               \
257
                VSB_printf(tl->sb, " \"%s\"", #l);
258
259
#include "tbl/vcl_returns.h"
260 25
        VSB_cat(tl->sb, "\n");
261 2343075
}
262
263
int
264 66950
vcc_CheckAction(struct vcc *tl)
265
{
266
267 66950
        VCC_WalkSymbols(tl, vcc_checkaction, SYM_MAIN, SYM_SUB);
268 66950
        return (tl->err);
269
}
270
271
/*--------------------------------------------------------------------*/
272
273
static struct procuse *
274 4423600
vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
275
{
276
277 4423600
        if (pu->mask || pu->use != XREF_WRITE)
278 4423275
                return (NULL);
279
280 325
        if (pu->sym->r_methods == 0) {
281 25
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
282 25
                VSB_cat(tl->sb, "Variable cannot be set.\n");
283 25
                return (NULL);
284
        }
285
286 300
        if (!(pu->sym->r_methods & m->bitval)) {
287 50
                pu->use = XREF_READ; /* NB: change the error message. */
288 50
                return (pu);
289
        }
290
291 250
        vcc_ErrWhere2(tl, pu->t1, pu->t2);
292 250
        VSB_cat(tl->sb, "Variable is read only.\n");
293 250
        return (NULL);
294 4423600
}
295
296
static struct procuse *
297 7321925
vcc_FindIllegalUse(struct vcc *tl, struct proc *p, const struct method *m)
298
{
299 7321925
        struct procuse *pu, *pw, *r = NULL;
300
301 21795725
        VTAILQ_FOREACH(pu, &p->uses, list) {
302 14473800
                p->okmask &= pu->mask;
303 14473800
                if (m == NULL)
304 10050200
                        continue;
305 4423600
                pw = vcc_illegal_write(tl, pu, m);
306 4423600
                if (r != NULL)
307 175
                        continue;
308 4423425
                if (tl->err)
309 275
                        r = pw;
310 4423150
                else if (!(pu->mask & m->bitval))
311 725
                        r = pu;
312 4423425
        }
313 7321925
        return (r);
314
}
315
316
static int
317 4992675
vcc_CheckUseRecurse(struct vcc *tl, struct proc *p,
318
    const struct method *m)
319
{
320
        struct proccall *pc;
321
        struct procuse *pu;
322
323 4992675
        pu = vcc_FindIllegalUse(tl, p, m);
324 4992675
        if (pu != NULL) {
325 75
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
326 150
                VSB_printf(tl->sb, "%s from subroutine '%s'.\n",
327 75
                    pu->use->err, m->name);
328 150
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
329 75
                    PF(pu->fm->name));
330 75
                vcc_ErrWhere(tl, p->name);
331 75
                return (1);
332
        }
333 4992600
        if (tl->err)
334 25
                return (1);
335 7656775
        VTAILQ_FOREACH(pc, &p->calls, list) {
336 2664325
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
337 250
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
338 125
                            PF(p->name));
339 125
                        vcc_ErrWhere(tl, pc->t);
340 125
                        return (1);
341
                }
342 2664200
                p->okmask &= pc->sym->proc->okmask;
343 2664200
        }
344 4992450
        return (0);
345 4992675
}
346
347
static void
348 2329250
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
349
{
350
        struct proc *p;
351
        struct procuse *pu;
352
353 2329250
        p = sym->proc;
354 2329250
        AN(p);
355 2329250
        pu = vcc_FindIllegalUse(tl, p, p->method);
356 2329250
        if (pu != NULL) {
357 650
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
358 1300
                VSB_printf(tl->sb, "%s in subroutine '%.*s'.",
359 650
                    pu->use->err, PF(p->name));
360 650
                VSB_cat(tl->sb, "\nAt: ");
361 650
                return;
362
        }
363 2328600
        ERRCHK(tl);
364 2328350
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
365 200
                VSB_printf(tl->sb,
366 100
                    "\n...which is the \"%s\" subroutine\n", p->method->name);
367 100
                return;
368
        }
369 2329250
}
370
371
/*
372
 * Used from a second symbol walk because vcc_checkuses is more precise for
373
 * subroutines called from methods. We catch here subs used for dynamic calls
374
 * and with vcc_err_unref = off
375
 */
376
static void
377 2305375
vcc_checkpossible(struct vcc *tl, const struct symbol *sym)
378
{
379
        struct proc *p;
380
381 2305375
        p = sym->proc;
382 2305375
        AN(p);
383
384 2305375
        if (p->okmask != 0)
385 2305325
                return;
386
387 50
        VSB_cat(tl->sb, "Impossible Subroutine");
388 50
        vcc_ErrWhere(tl, p->name);
389 2305375
}
390
391
int
392 66875
vcc_CheckUses(struct vcc *tl)
393
{
394
395 66875
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_MAIN, SYM_SUB);
396 66875
        if (tl->err)
397 1000
                return (tl->err);
398 65875
        VCC_WalkSymbols(tl, vcc_checkpossible, SYM_MAIN, SYM_SUB);
399 65875
        return (tl->err);
400 66875
}
401
402
/*---------------------------------------------------------------------*/
403
404
static void v_matchproto_(symwalk_f)
405 4850
vcc_instance_info(struct vcc *tl, const struct symbol *sym)
406
{
407
408 4850
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
409 4850
        AN(sym->rname);
410 4850
        Fc(tl, 0, "\t{ .p = (uintptr_t *)&%s, .name = \"", sym->rname);
411 4850
        VCC_SymName(tl->fc, sym);
412 4850
        Fc(tl, 0, "\" },\n");
413 4850
}
414
415
void
416 29275
VCC_InstanceInfo(struct vcc *tl)
417
{
418 29275
        Fc(tl, 0, "\nstatic const struct vpi_ii VGC_instance_info[] = {\n");
419 29275
        VCC_WalkSymbols(tl, vcc_instance_info, SYM_MAIN, SYM_INSTANCE);
420 29275
        Fc(tl, 0, "\t{ .p = NULL, .name = \"\" }\n");
421 29275
        Fc(tl, 0, "};\n");
422 29275
}
423
424
/*---------------------------------------------------------------------*/
425
426
static int sym_type_len;
427
428
static void v_matchproto_(symwalk_f)
429 6373675
vcc_xreftable_len(struct vcc *tl, const struct symbol *sym)
430
{
431
        int len;
432
433 6373675
        (void)tl;
434 6373675
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
435 6373675
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
436 6373675
        len = strlen(sym->type->name);
437 6373675
        if (sym_type_len < len)
438 182750
                sym_type_len = len;
439 6373675
}
440
441
static void v_matchproto_(symwalk_f)
442 6373675
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
443
{
444
445 6373675
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
446 6373675
        CHECK_OBJ_NOTNULL(sym->kind, KIND_MAGIC);
447 6373675
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
448 6373675
        Fc(tl, 0, " * %-8s ", sym->kind->name);
449 6373675
        Fc(tl, 0, " %-*s ", sym_type_len, sym->type->name);
450 6373675
        Fc(tl, 0, " %2u %2u ", sym->lorev, sym->hirev);
451 6373675
        VCC_SymName(tl->fc, sym);
452 6373675
        if (sym->wildcard != NULL)
453 175650
                Fc(tl, 0, "*");
454 6373675
        Fc(tl, 0, "\n");
455 6373675
}
456
457
void
458 29275
VCC_XrefTable(struct vcc *tl)
459
{
460
461
#define VCC_NAMESPACE(U, l)                                             \
462
        Fc(tl, 0, "\n/*\n * Symbol Table " #U "\n *\n");                \
463
        sym_type_len = 0;                                               \
464
        VCC_WalkSymbols(tl, vcc_xreftable_len, SYM_##U, SYM_NONE);      \
465
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_##U, SYM_NONE);          \
466
        Fc(tl, 0, "*/\n\n");
467
#include "vcc_namespace.h"
468 29275
}
469
470
/*---------------------------------------------------------------------
471
 * mark vmod as referenced, return NULL if not yet marked, vmod if marked
472
 */
473
474
const char *
475 3375
vcc_MarkPriv(struct vcc *tl, struct procprivhead *head,
476
    const char *vmod)
477
{
478
        struct procpriv *pp;
479
480 3375
        AN(vmod);
481
482 3375
        VTAILQ_FOREACH(pp, head, list) {
483 2300
                if (pp->vmod == vmod)
484 2300
                        return (vmod);
485 0
                AN(strcmp(pp->vmod, vmod));
486 0
        }
487
488 1075
        pp = TlAlloc(tl, sizeof *pp);
489 1075
        assert(pp != NULL);
490 1075
        pp->vmod = vmod;
491 1075
        VTAILQ_INSERT_TAIL(head, pp, list);
492 1075
        return (NULL);
493 3375
}