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 80
 * 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 80
 *    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 80
 * 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 80
 * 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
 * both defined and referenced.  Complaints about referenced but undefined
34
 * 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 80
#include "vcc_compile.h"
45
46
/*--------------------------------------------------------------------*/
47
48
struct proccall {
49
        VTAILQ_ENTRY(proccall)  list;
50 80
        struct symbol           *sym;
51
        struct token            *t;
52
        struct proc             *fm;
53
};
54 80
55
struct procuse {
56
        VTAILQ_ENTRY(procuse)   list;
57
        const struct token      *t1;
58 80
        const struct token      *t2;
59
        const struct symbol     *sym;
60
        const struct xrefuse    *use;
61
        unsigned                mask;
62
        struct proc             *fm;
63 80
};
64
65
/*--------------------------------------------------------------------*/
66
67
static void
68 21536280
vcc_checkref(struct vcc *tl, const struct symbol *sym)
69
{
70 80
71 21536280
        if (sym->noref)
72 19212720
                return;
73 2323560
        if (sym->ndef == 0 && sym->nref != 0) {
74 120
                AN(sym->ref_b);
75 320
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
76 120
                    sym->kind->name, PF(sym->ref_b));
77 120
                vcc_ErrWhere(tl, sym->ref_b);
78 2323560
        } else if (sym->ndef != 0 && sym->nref == 0) {
79 5160
                AN(sym->def_b);
80 10160
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
81 5080
                    sym->kind->name, PF(sym->def_b));
82 5080
                vcc_ErrWhere(tl, sym->def_b);
83 5080
                if (!tl->err_unref)
84 4840
                        vcc_Warn(tl);
85 5080
        }
86 21536280
}
87
88
int
89 109400
vcc_CheckReferences(struct vcc *tl)
90
{
91
92 109320
        VCC_WalkSymbols(tl, vcc_checkref, SYM_MAIN, SYM_NONE);
93 109320
        return (tl->err);
94 80
}
95
96
/*--------------------------------------------------------------------
97
 * Returns checks
98
 */
99
100
const struct xrefuse XREF_READ[1] = {{"xref_read", "Not available"}};
101
const struct xrefuse XREF_WRITE[1] = {{"xref_write", "Cannot be set"}};
102
const struct xrefuse XREF_UNSET[1] = {{"xref_unset", "Cannot be unset"}};
103
const struct xrefuse XREF_ACTION[1] = {{"xref_action", "Not a valid action"}};
104 80
105
void
106 6324600
vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
107
    const struct symbol *sym, const struct xrefuse *use)
108
{
109
        struct procuse *pu;
110
111 6324600
        AN(tl->curproc);
112 6324600
        pu = TlAlloc(tl, sizeof *pu);
113 6324600
        AN(pu);
114 6324600
        AN(sym);
115 6324600
        AN(use);
116 6324600
        AN(use->name);
117 6324600
        pu->t1 = t1;
118 6324600
        pu->t2 = t2;
119 6324600
        if (pu->t2 == NULL) {
120 5120960
                pu->t2 = vcc_PeekTokenFrom(tl, t1);
121 5120960
                AN(pu->t2);
122 5120960
        }
123 6324600
        pu->sym = sym;
124 6324600
        pu->use = use;
125 6324600
        pu->fm = tl->curproc;
126
127 6324600
        if (pu->use == XREF_READ)
128 4784040
                pu->mask = sym->r_methods;
129 1540560
        else if (pu->use == XREF_WRITE)
130 1092160
                pu->mask = sym->w_methods;
131 448400
        else if (pu->use == XREF_UNSET)
132 111480
                pu->mask = sym->u_methods;
133 336920
        else if (pu->use == XREF_ACTION)
134 336920
                pu->mask = sym->action_mask;
135
        else
136 0
                WRONG("wrong xref use");
137
138 6324600
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
139 6324600
}
140
141
void
142 2629080
vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym)
143
{
144
        struct proccall *pc;
145
146 2629080
        AN(sym);
147 2629080
        pc = TlAlloc(tl, sizeof *pc);
148 2629080
        AN(pc);
149 2629080
        pc->sym = sym;
150 2629080
        pc->t = t;
151 2629080
        pc->fm = tl->curproc;
152 2629080
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
153 2629080
}
154
155
void
156 2428400
vcc_ProcAction(struct proc *p, unsigned returns, unsigned mask, struct token *t)
157
{
158
159 2428400
        assert(returns < VCL_RET_MAX);
160 2428400
        p->ret_bitmap |= (1U << returns);
161 2428400
        p->okmask &= mask;
162
        /* Record the first instance of this return */
163 2428400
        if (p->return_tok[returns] == NULL)
164 2421840
                p->return_tok[returns] = t;
165 2428400
}
166
167
static int
168 8174640
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
169
{
170
        unsigned u;
171
        struct proccall *pc;
172
173 8174640
        AN(p);
174 8174640
        if (p->active) {
175 80
                VSB_cat(tl->sb, "Subroutine recurses on\n");
176 80
                vcc_ErrWhere(tl, p->name);
177 80
                return (1);
178
        }
179 8174560
        u = p->ret_bitmap & ~bitmap;
180 8174560
        if (u) {
181
182
#define VCL_RET_MAC(l, U, B)                                            \
183
                if (u & (1 << (VCL_RET_##U))) {                         \
184
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
185
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
186
                }
187
#include "tbl/vcl_returns.h"
188
189
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
190
                    PF(p->name));
191
                vcc_ErrWhere(tl, p->name);
192
                return (1);
193
        }
194
195
        // more references than calls -> sub is referenced for dynamic calls
196 8174520
        u = (p->sym->nref > p->called);
197
198 8174520
        p->active = 1;
199 12535680
        VTAILQ_FOREACH(pc, &p->calls, list) {
200 4361320
                if (pc->sym->proc == NULL) {
201 0
                        VSB_printf(tl->sb, "Subroutine %s does not exist\n",
202 0
                            pc->sym->name);
203 0
                        vcc_ErrWhere(tl, pc->t);
204 0
                        return (1);
205
                }
206 4361320
                pc->sym->proc->calledfrom |= p->calledfrom;
207 4361320
                pc->sym->proc->called++;
208 4361320
                pc->sym->nref += u;
209 4361320
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
210 320
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
211 160
                            PF(p->name));
212 160
                        vcc_ErrWhere(tl, pc->t);
213 160
                        return (1);
214
                }
215 4361160
                p->okmask &= pc->sym->proc->okmask;
216 4361160
        }
217 8174360
        p->active = 0;
218 8174360
        return (0);
219 8174640
}
220
221
/*--------------------------------------------------------------------*/
222
223
static void
224 3813320
vcc_checkaction(struct vcc *tl, const struct symbol *sym)
225
{
226
        struct proc *p;
227
        unsigned bitmap;
228
229 3813320
        p = sym->proc;
230 3813320
        AN(p);
231 3813320
        AN(p->name);
232
233 3813320
        if (p->method == NULL) {
234 2289040
                bitmap = ~0U;
235 2289040
        } else {
236 1524280
                bitmap = p->method->ret_bitmap;
237 1524280
                p->calledfrom = p->method->bitval;
238
        }
239
240 3813320
        if (! vcc_CheckActionRecurse(tl, p, bitmap))
241 3813200
                return;
242
243 120
        tl->err = 1;
244 120
        if (p->method == NULL)
245 80
                return;
246
247 80
        VSB_printf(tl->sb,
248 40
                   "\n...which is the \"%s\" subroutine\n", p->method->name);
249 40
        VSB_cat(tl->sb, "Legal returns are:");
250
#define VCL_RET_MAC(l, U, B)                                            \
251
        if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))               \
252
                VSB_printf(tl->sb, " \"%s\"", #l);
253
254
#include "tbl/vcl_returns.h"
255
        VSB_cat(tl->sb, "\n");
256
}
257
258
int
259 108960
vcc_CheckAction(struct vcc *tl)
260
{
261
262 108960
        VCC_WalkSymbols(tl, vcc_checkaction, SYM_MAIN, SYM_SUB);
263 108960
        return (tl->err);
264
}
265
266
/*--------------------------------------------------------------------*/
267
268
static struct procuse *
269 7198080
vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
270
{
271
272 7198080
        if (pu->mask || pu->use != XREF_WRITE)
273 7197560
                return (NULL);
274
275 520
        if (pu->sym->r_methods == 0) {
276 40
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
277 40
                VSB_cat(tl->sb, "Variable cannot be set.\n");
278 40
                return (NULL);
279
        }
280
281 480
        if (!(pu->sym->r_methods & m->bitval)) {
282 80
                pu->use = XREF_READ; /* NB: change the error message. */
283 80
                return (pu);
284
        }
285
286 400
        vcc_ErrWhere2(tl, pu->t1, pu->t2);
287 400
        VSB_cat(tl->sb, "Variable is read only.\n");
288 400
        return (NULL);
289 7198080
}
290
291
static struct procuse *
292 11917480
vcc_FindIllegalUse(struct vcc *tl, struct proc *p, const struct method *m)
293
{
294 11917480
        struct procuse *pu, *pw, *r = NULL;
295
296 35473720
        VTAILQ_FOREACH(pu, &p->uses, list) {
297 23556240
                p->okmask &= pu->mask;
298 23556240
                if (m == NULL)
299 16358160
                        continue;
300 7198080
                pw = vcc_illegal_write(tl, pu, m);
301 7198080
                if (r != NULL)
302 280
                        continue;
303 7197800
                if (tl->err)
304 440
                        r = pw;
305 7197360
                else if (!(pu->mask & m->bitval))
306 1160
                        r = pu;
307 7197800
        }
308 11917480
        return (r);
309
}
310
311
static int
312 8126280
vcc_CheckUseRecurse(struct vcc *tl, struct proc *p,
313
    const struct method *m)
314
{
315
        struct proccall *pc;
316
        struct procuse *pu;
317
318 8126280
        pu = vcc_FindIllegalUse(tl, p, m);
319 8126280
        if (pu != NULL) {
320 120
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
321 240
                VSB_printf(tl->sb, "%s from subroutine '%s'.\n",
322 120
                    pu->use->err, m->name);
323 240
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
324 120
                    PF(pu->fm->name));
325 120
                vcc_ErrWhere(tl, p->name);
326 120
                return (1);
327
        }
328 8126160
        if (tl->err)
329 40
                return (1);
330 12462440
        VTAILQ_FOREACH(pc, &p->calls, list) {
331 4336520
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
332 400
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
333 200
                            PF(p->name));
334 200
                        vcc_ErrWhere(tl, pc->t);
335 200
                        return (1);
336
                }
337 4336320
                p->okmask &= pc->sym->proc->okmask;
338 4336320
        }
339 8125920
        return (0);
340 8126280
}
341
342
static void
343 3791200
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
344
{
345
        struct proc *p;
346
        struct procuse *pu;
347
348 3791200
        p = sym->proc;
349 3791200
        AN(p);
350 3791200
        pu = vcc_FindIllegalUse(tl, p, p->method);
351 3791200
        if (pu != NULL) {
352 1040
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
353 2080
                VSB_printf(tl->sb, "%s in subroutine '%.*s'.",
354 1040
                    pu->use->err, PF(p->name));
355 1040
                VSB_cat(tl->sb, "\nAt: ");
356 1040
                return;
357
        }
358 3790160
        ERRCHK(tl);
359 3789760
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
360 320
                VSB_printf(tl->sb,
361 160
                    "\n...which is the \"%s\" subroutine\n", p->method->name);
362 160
                return;
363
        }
364 3791200
}
365
366
/*
367
 * Used from a second symbol walk because vcc_checkuses is more precise for
368
 * subroutines called from methods. We catch here subs used for dynamic calls
369
 * and with vcc_err_unref = off
370
 */
371
static void
372 3753000
vcc_checkpossible(struct vcc *tl, const struct symbol *sym)
373
{
374
        struct proc *p;
375
376 3753000
        p = sym->proc;
377 3753000
        AN(p);
378
379 3753000
        if (p->okmask != 0)
380 3752920
                return;
381
382 80
        VSB_cat(tl->sb, "Impossible Subroutine");
383 80
        vcc_ErrWhere(tl, p->name);
384 3753000
}
385
386
int
387 108840
vcc_CheckUses(struct vcc *tl)
388
{
389
390 108840
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_MAIN, SYM_SUB);
391 108840
        if (tl->err)
392 1600
                return (tl->err);
393 107240
        VCC_WalkSymbols(tl, vcc_checkpossible, SYM_MAIN, SYM_SUB);
394 107240
        return (tl->err);
395 108840
}
396
397
/*---------------------------------------------------------------------*/
398
399
static void v_matchproto_(symwalk_f)
400 7760
vcc_instance_info(struct vcc *tl, const struct symbol *sym)
401
{
402
403 7760
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
404 7760
        AN(sym->rname);
405 7760
        Fc(tl, 0, "\t{ .p = (uintptr_t *)&%s, .name = \"", sym->rname);
406 7760
        VCC_SymName(tl->fc, sym);
407 7760
        Fc(tl, 0, "\" },\n");
408 7760
}
409
410
void
411 47760
VCC_InstanceInfo(struct vcc *tl)
412
{
413 47760
        Fc(tl, 0, "\nstatic const struct vpi_ii VGC_instance_info[] = {\n");
414 47760
        VCC_WalkSymbols(tl, vcc_instance_info, SYM_MAIN, SYM_INSTANCE);
415 47760
        Fc(tl, 0, "\t{ .p = NULL, .name = \"\" }\n");
416 47760
        Fc(tl, 0, "};\n");
417 47760
}
418
419
/*---------------------------------------------------------------------*/
420
421
static int sym_type_len;
422
423
static void v_matchproto_(symwalk_f)
424 10397840
vcc_xreftable_len(struct vcc *tl, const struct symbol *sym)
425
{
426
        int len;
427
428 10397840
        (void)tl;
429 10397840
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
430 10397840
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
431 10397840
        len = strlen(sym->type->name);
432 10397840
        if (sym_type_len < len)
433 298240
                sym_type_len = len;
434 10397840
}
435
436
static void v_matchproto_(symwalk_f)
437 10397840
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
438
{
439
440 10397840
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
441 10397840
        CHECK_OBJ_NOTNULL(sym->kind, KIND_MAGIC);
442 10397840
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
443 10397840
        Fc(tl, 0, " * %-8s ", sym->kind->name);
444 10397840
        Fc(tl, 0, " %-*s ", sym_type_len, sym->type->name);
445 10397840
        Fc(tl, 0, " %2u %2u ", sym->lorev, sym->hirev);
446 10397840
        VCC_SymName(tl->fc, sym);
447 10397840
        if (sym->wildcard != NULL)
448 286560
                Fc(tl, 0, "*");
449 10397840
        Fc(tl, 0, "\n");
450 10397840
}
451
452
void
453 47760
VCC_XrefTable(struct vcc *tl)
454
{
455
456
#define VCC_NAMESPACE(U, l)                                             \
457
        Fc(tl, 0, "\n/*\n * Symbol Table " #U "\n *\n");                \
458
        sym_type_len = 0;                                               \
459
        VCC_WalkSymbols(tl, vcc_xreftable_len, SYM_##U, SYM_NONE);      \
460
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_##U, SYM_NONE);          \
461
        Fc(tl, 0, "*/\n\n");
462
#include "vcc_namespace.h"
463
}