varnish-cache/lib/libvcc/vcc_xref.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * This file contains code for two cross-reference or consistency checks.
30
 *
31
 * The first check is simply that all subroutine, acls and backends are
32
 * both defined and referenced.  Complaints about referenced but undefined
33
 * or defined but unreferenced objects will be emitted.
34
 *
35
 * The second check recursively decends through subroutine calls to make
36
 * sure that action actions are correct for the methods through which
37
 * they are called.
38
 */
39
40
#include "config.h"
41
42
#include <string.h>
43
#include "vcc_compile.h"
44
45
/*--------------------------------------------------------------------*/
46
47
struct proccall {
48
        VTAILQ_ENTRY(proccall)  list;
49
        struct symbol           *sym;
50
        struct token            *t;
51
        struct proc             *fm;
52
};
53
54
struct procuse {
55
        VTAILQ_ENTRY(procuse)   list;
56
        const struct token      *t1;
57
        const struct token      *t2;
58
        unsigned                mask;
59
        const char              *use;
60
        struct proc             *fm;
61
};
62
63
struct procpriv {
64
        VTAILQ_ENTRY(procpriv)  list;
65
        const char              *vmod;
66
};
67
68
/*--------------------------------------------------------------------*/
69
70
static void
71 567716
vcc_checkref(struct vcc *tl, const struct symbol *sym)
72
{
73
74 567716
        if (sym->noref)
75 536336
                return;
76 31380
        if (sym->ndef == 0 && sym->nref != 0) {
77 4
                AN(sym->ref_b);
78 12
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
79 12
                    sym->kind->name, PF(sym->ref_b));
80 4
                vcc_ErrWhere(tl, sym->ref_b);
81 31376
        } else if (sym->ndef != 0 && sym->nref == 0) {
82 432
                AN(sym->def_b);
83 1296
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
84 1296
                    sym->kind->name, PF(sym->def_b));
85 432
                vcc_ErrWhere(tl, sym->def_b);
86 432
                if (!tl->err_unref) {
87 408
                        VSB_printf(tl->sb, "(That was just a warning)\n");
88 408
                        tl->err = 0;
89
                }
90
        }
91
}
92
93
int
94 3620
vcc_CheckReferences(struct vcc *tl)
95
{
96
97 3620
        VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
98 3620
        return (tl->err);
99
}
100
101
/*--------------------------------------------------------------------
102
 * Returns checks
103
 */
104
105
void
106 213832
vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
107
    unsigned mask, const char *use)
108
{
109
        struct procuse *pu;
110
111 213832
        if (tl->curproc == NULL)        /* backend */
112 0
                return;
113 213832
        pu = TlAlloc(tl, sizeof *pu);
114 213832
        assert(pu != NULL);
115 213832
        pu->t1 = t1;
116 213832
        pu->t2 = t2;
117 213832
        if (pu->t2 == NULL)
118 173364
                pu->t2 = VTAILQ_NEXT(t1, list);
119 213832
        pu->mask = mask;
120 213832
        pu->use = use;
121 213832
        pu->fm = tl->curproc;
122 213832
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
123
}
124
125
void
126 56
vcc_AddCall(struct vcc *tl, struct symbol *sym)
127
{
128
        struct proccall *pc;
129
130 56
        AN(sym);
131 56
        pc = TlAlloc(tl, sizeof *pc);
132 56
        assert(pc != NULL);
133 56
        pc->sym = sym;
134 56
        pc->t = tl->t;
135 56
        pc->fm = tl->curproc;
136 56
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
137 56
}
138
139
void
140 81056
vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
141
{
142
143 81056
        assert(returns < VCL_RET_MAX);
144 81056
        p->ret_bitmap |= (1U << returns);
145
        /* Record the first instance of this return */
146 81056
        if (p->return_tok[returns] == NULL)
147 65604
                p->return_tok[returns] = t;
148 81056
}
149
150
static int
151 50332
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
152
{
153
        unsigned u;
154
        struct proccall *pc;
155
156 50332
        AN(p);
157 50332
        if (p->active) {
158 8
                VSB_printf(tl->sb, "Function recurses on\n");
159 8
                vcc_ErrWhere(tl, p->name);
160 8
                return (1);
161
        }
162 50324
        u = p->ret_bitmap & ~bitmap;
163 50324
        if (u) {
164
165
#define VCL_RET_MAC(l, U, B)                                            \
166
                if (u & (1 << (VCL_RET_##U))) {                         \
167
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
168
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
169
                }
170
#include "tbl/vcl_returns.h"
171
172 8
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
173 8
                    PF(p->name));
174 4
                vcc_ErrWhere(tl, p->name);
175 4
                return (1);
176
        }
177 50320
        p->active = 1;
178 50352
        VTAILQ_FOREACH(pc, &p->calls, list) {
179 56
                if (pc->sym->proc == NULL) {
180 0
                        VSB_printf(tl->sb, "Function %s does not exist\n",
181 0
                            pc->sym->name);
182 0
                        vcc_ErrWhere(tl, pc->t);
183 0
                        return (1);
184
                }
185 56
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
186 24
                        VSB_printf(tl->sb, "\n...called from \"%s\"\n",
187 24
                            pc->sym->name);
188 24
                        vcc_ErrWhere(tl, pc->t);
189 24
                        return (1);
190
                }
191
        }
192 50296
        p->active = 0;
193 50296
        p->called++;
194 50296
        return (0);
195
}
196
197
/*--------------------------------------------------------------------*/
198
199
static void
200 50324
vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
201
{
202
        struct proc *p;
203
204 50324
        p = sym->proc;
205 50324
        AN(p);
206 50324
        AN(p->name);
207 50324
        if (p->method == NULL)
208 48
                return;
209 50276
        if (vcc_CheckActionRecurse(tl, p, p->method->ret_bitmap)) {
210 12
                VSB_printf(tl->sb,
211 12
                    "\n...which is the \"%s\" method\n", p->method->name);
212 12
                VSB_printf(tl->sb, "Legal returns are:");
213
#define VCL_RET_MAC(l, U, B)                                            \
214
                if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))       \
215
                        VSB_printf(tl->sb, " \"%s\"", #l);
216
217
#include "tbl/vcl_returns.h"
218 12
                VSB_printf(tl->sb, "\n");
219 12
                tl->err = 1;
220
        }
221
222
}
223
224
static void
225 50152
vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
226
{
227
        struct proc *p;
228
229 50152
        p = sym->proc;
230 50152
        AN(p);
231
232 50152
        if (p->called)
233 50148
                return;
234 4
        VSB_printf(tl->sb, "Function unused\n");
235 4
        vcc_ErrWhere(tl, p->name);
236 4
        if (!tl->err_unref) {
237 4
                VSB_printf(tl->sb, "(That was just a warning)\n");
238 4
                tl->err = 0;
239
        }
240
}
241
242
int
243 3592
vcc_CheckAction(struct vcc *tl)
244
{
245
246 3592
        VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
247 3592
        if (tl->err)
248 12
                return (tl->err);
249 3580
        VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
250 3580
        return (tl->err);
251
}
252
253
/*--------------------------------------------------------------------*/
254
255
static struct procuse *
256 100112
vcc_FindIllegalUse(const struct proc *p, const struct method *m)
257
{
258
        struct procuse *pu;
259
260 521312
        VTAILQ_FOREACH(pu, &p->uses, list)
261 421224
                if (!(pu->mask & m->bitval))
262 24
                        return (pu);
263 100088
        return (NULL);
264
}
265
266
static int
267 50060
vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
268
    const struct method *m)
269
{
270
        struct proccall *pc;
271
        struct procuse *pu;
272
273 50060
        pu = vcc_FindIllegalUse(p, m);
274 50060
        if (pu != NULL) {
275 0
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
276 0
                VSB_printf(tl->sb, "%s from method '%s'.\n",
277
                    pu->use, m->name);
278 0
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
279 0
                    PF(pu->fm->name));
280 0
                vcc_ErrWhere(tl, p->name);
281 0
                return (1);
282
        }
283 50092
        VTAILQ_FOREACH(pc, &p->calls, list) {
284 32
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
285 0
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
286 0
                            PF(pc->fm->name));
287 0
                        vcc_ErrWhere(tl, pc->t);
288 0
                        return (1);
289
                }
290
        }
291 50060
        return (0);
292
}
293
294
static void
295 50084
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
296
{
297
        struct proc *p;
298
        struct procuse *pu;
299
300 50084
        p = sym->proc;
301 50084
        AN(p);
302 50084
        if (p->method == NULL)
303 32
                return;
304 50052
        pu = vcc_FindIllegalUse(p, p->method);
305 50052
        if (pu != NULL) {
306 24
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
307 48
                VSB_printf(tl->sb, "%s in method '%.*s'.",
308 48
                    pu->use, PF(p->name));
309 24
                VSB_cat(tl->sb, "\nAt: ");
310 24
                return;
311
        }
312 50028
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
313 0
                VSB_printf(tl->sb,
314 0
                    "\n...which is the \"%s\" method\n", p->method->name);
315 0
                return;
316
        }
317
}
318
319
int
320 3580
vcc_CheckUses(struct vcc *tl)
321
{
322
323 3580
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
324 3580
        return (tl->err);
325
}
326
327
/*---------------------------------------------------------------------*/
328
329
static void
330 1021420
vcc_pnam(struct vcc *tl, const struct symbol *sym)
331
{
332
333 1021420
        if (sym->parent != tl->symbols) {
334 460672
                vcc_pnam(tl, sym->parent);
335 460672
                Fc(tl, 0, ".");
336
        }
337 1021420
        Fc(tl, 0, "%s", sym->name);
338 1021420
}
339
340
static void v_matchproto_(symwalk_f)
341 560748
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
342
{
343
344 560748
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
345 560748
        CHECK_OBJ_NOTNULL(sym->kind, KIND_MAGIC);
346 560748
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
347 560748
        Fc(tl, 0, " * %-8s ", sym->kind->name);
348 560748
        Fc(tl, 0, " %-9s ", sym->type->name);
349 560748
        Fc(tl, 0, " %2u %2u ", sym->lorev, sym->hirev);
350 560748
        vcc_pnam(tl, sym);
351 560748
        if (sym->wildcard != NULL)
352 22640
                Fc(tl, 0, "*");
353 560748
        Fc(tl, 0, "\n");
354 560748
}
355
356
void
357 3556
VCC_XrefTable(struct vcc *tl)
358
{
359
360 3556
        Fc(tl, 0, "\n/*\n * Symbol Table\n *\n");
361 3556
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_NONE);
362 3556
        Fc(tl, 0, "*/\n\n");
363 3556
}
364
365
/*---------------------------------------------------------------------
366
 * mark vmod as referenced, return NULL if not yet marked, vmod if marked
367
 */
368
369
const char *
370 692
vcc_MarkPriv(struct vcc *tl, struct procprivhead *head,
371
    const char *vmod)
372
{
373
        struct procpriv *pp;
374
375 692
        AN(vmod);
376
377 708
        VTAILQ_FOREACH(pp, head, list) {
378 596
                if (pp->vmod == vmod)
379 580
                        return (vmod);
380 16
                AN(strcmp(pp->vmod, vmod));
381
        }
382
383 112
        pp = TlAlloc(tl, sizeof *pp);
384 112
        assert(pp != NULL);
385 112
        pp->vmod = vmod;
386 112
        VTAILQ_INSERT_TAIL(head, pp, list);
387 112
        return (NULL);
388
}