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 "vcc_compile.h"
43
44
/*--------------------------------------------------------------------*/
45
46
struct proccall {
47
        VTAILQ_ENTRY(proccall)  list;
48
        struct symbol           *sym;
49
        struct token            *t;
50
};
51
52
struct procuse {
53
        VTAILQ_ENTRY(procuse)   list;
54
        const struct token      *t;
55
        unsigned                mask;
56
        const char              *use;
57
};
58
59
/*--------------------------------------------------------------------
60
 * Keep track of definitions and references
61
 */
62
63
struct symbol *
64 23704
vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind kind)
65
{
66
        struct symbol *sym;
67
68 23704
        sym = VCC_SymbolTok(tl, NULL, t, kind, 1);
69 23704
        if (sym->ref_b == NULL)
70 23468
                sym->ref_b = t;
71 23704
        AN(sym);
72 23704
        sym->nref++;
73 23704
        return (sym);
74
}
75
76
struct symbol *
77 45170
vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind kind)
78
{
79
        struct symbol *sym;
80
81 45170
        sym = VCC_SymbolTok(tl, NULL, t, kind, 1);
82 45170
        if (sym->def_b == NULL)
83 21748
                sym->def_b = t;
84 45170
        AN(sym);
85 45170
        sym->ndef++;
86 45170
        return (sym);
87
}
88
89
/*--------------------------------------------------------------------*/
90
91
static void
92 204458
vcc_checkref(struct vcc *tl, const struct symbol *sym)
93
{
94
95 204458
        if (sym->ndef == 0 && sym->nref != 0) {
96 2
                AN(sym->ref_b);
97 4
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
98 4
                    VCC_SymKind(tl, sym), PF(sym->ref_b));
99 2
                vcc_ErrWhere(tl, sym->ref_b);
100 204456
        } else if (sym->ndef != 0 && sym->nref == 0) {
101 16
                AN(sym->def_b);
102 32
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
103 32
                    VCC_SymKind(tl, sym), PF(sym->def_b));
104 16
                vcc_ErrWhere(tl, sym->def_b);
105 16
                if (!tl->err_unref) {
106 6
                        VSB_printf(tl->sb, "(That was just a warning)\n");
107 6
                        tl->err = 0;
108
                }
109
        }
110 204458
}
111
112
int
113 1540
vcc_CheckReferences(struct vcc *tl)
114
{
115
116 1540
        VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
117 1540
        return (tl->err);
118
}
119
120
/*--------------------------------------------------------------------
121
 * Returns checks
122
 */
123
124
void
125 86202
vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
126
    const char *use)
127
{
128
        struct procuse *pu;
129
130 86202
        if (tl->curproc == NULL)        /* backend */
131 86202
                return;
132 86202
        pu = TlAlloc(tl, sizeof *pu);
133 86202
        assert(pu != NULL);
134 86202
        pu->t = t;
135 86202
        pu->mask = mask;
136 86202
        pu->use = use;
137 86202
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
138
}
139
140
void
141 24
vcc_AddCall(struct vcc *tl, struct token *t)
142
{
143
        struct proccall *pc;
144
145 24
        pc = TlAlloc(tl, sizeof *pc);
146 24
        assert(pc != NULL);
147 24
        pc->sym = VCC_SymbolTok(tl, NULL, t, SYM_SUB, 1);
148 24
        AN(pc->sym);
149 24
        pc->t = t;
150 24
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
151 24
}
152
153
void
154 32934
vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
155
{
156
157 32934
        assert(returns < VCL_RET_MAX);
158 32934
        p->ret_bitmap |= (1U << returns);
159
        /* Record the first instance of this return */
160 32934
        if (p->return_tok[returns] == NULL)
161 27910
                p->return_tok[returns] = t;
162 32934
}
163
164
static int
165 21410
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
166
{
167
        unsigned u;
168
        struct proccall *pc;
169
170 21410
        AN(p);
171 21410
        if (p->active) {
172 4
                VSB_printf(tl->sb, "Function recurses on\n");
173 4
                vcc_ErrWhere(tl, p->name);
174 4
                return (1);
175
        }
176 21406
        u = p->ret_bitmap & ~bitmap;
177 21406
        if (u) {
178
179
#define VCL_RET_MAC(l, U, B)                                            \
180
                if (u & (1 << (VCL_RET_##U))) {                         \
181
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
182
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
183
                }
184
#include "tbl/vcl_returns.h"
185
186 4
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
187 4
                    PF(p->name));
188 2
                vcc_ErrWhere(tl, p->name);
189 2
                return (1);
190
        }
191 21404
        p->active = 1;
192 21416
        VTAILQ_FOREACH(pc, &p->calls, list) {
193 24
                if (pc->sym->proc == NULL) {
194 0
                        VSB_printf(tl->sb, "Function %s does not exist\n",
195 0
                            pc->sym->name);
196 0
                        vcc_ErrWhere(tl, pc->t);
197 0
                        return (1);
198
                }
199 24
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
200 12
                        VSB_printf(tl->sb, "\n...called from \"%s\"\n",
201 12
                            pc->sym->name);
202 12
                        vcc_ErrWhere(tl, pc->t);
203 12
                        return (1);
204
                }
205
        }
206 21392
        p->active = 0;
207 21392
        p->called++;
208 21392
        return (0);
209
}
210
211
/*--------------------------------------------------------------------*/
212
213
static void
214 21406
vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
215
{
216
        struct proc *p;
217
218 21406
        p = sym->proc;
219 21406
        AN(p);
220 21406
        AN(p->name);
221 21406
        if(p->method == NULL)
222 21426
                return;
223 21386
        if (vcc_CheckActionRecurse(tl, p, p->method->ret_bitmap)) {
224 6
                VSB_printf(tl->sb,
225 6
                    "\n...which is the \"%s\" method\n", p->method->name);
226 6
                VSB_printf(tl->sb, "Legal returns are:");
227
#define VCL_RET_MAC(l, U, B)                                            \
228
                if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))       \
229
                        VSB_printf(tl->sb, " \"%s\"", #l);
230
231
#include "tbl/vcl_returns.h"
232 6
                VSB_printf(tl->sb, "\n");
233 6
                tl->err = 1;
234
        }
235
236
}
237
238
static void
239 21320
vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
240
{
241
        struct proc *p;
242
243 21320
        p = sym->proc;
244 21320
        AN(p);
245
246 21320
        if (p->called)
247 42638
                return;
248 2
        VSB_printf(tl->sb, "Function unused\n");
249 2
        vcc_ErrWhere(tl, p->name);
250 2
        if (!tl->err_unref) {
251 2
                VSB_printf(tl->sb, "(That was just a warning)\n");
252 2
                tl->err = 0;
253
        }
254
}
255
256
int
257 1528
vcc_CheckAction(struct vcc *tl)
258
{
259
260 1528
        VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
261 1528
        if (tl->err)
262 6
                return (tl->err);
263 1522
        VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
264 1522
        return (tl->err);
265
}
266
267
/*--------------------------------------------------------------------*/
268
269
static struct procuse *
270 42548
vcc_FindIllegalUse(const struct proc *p, const struct method *m)
271
{
272
        struct procuse *pu;
273
274 212180
        VTAILQ_FOREACH(pu, &p->uses, list)
275 169644
                if (!(pu->mask & m->bitval))
276 12
                        return (pu);
277 42536
        return (NULL);
278
}
279
280
static int
281 21274
vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
282
    const struct method *m)
283
{
284
        struct proccall *pc;
285
        struct procuse *pu;
286
287 21274
        pu = vcc_FindIllegalUse(p, m);
288 21274
        if (pu != NULL) {
289 0
                VSB_printf(tl->sb,
290
                    "'%.*s': %s from method '%.*s'.\n",
291 0
                    PF(pu->t), pu->use, PF(p->name));
292 0
                vcc_ErrWhere(tl, pu->t);
293 0
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
294 0
                    PF(p->name));
295 0
                vcc_ErrWhere(tl, p->name);
296 0
                return (1);
297
        }
298 21286
        VTAILQ_FOREACH(pc, &p->calls, list) {
299 12
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
300 0
                        VSB_printf(tl->sb, "\n...called from \"%s\"\n",
301 0
                            pc->sym->name);
302 0
                        vcc_ErrWhere(tl, pc->t);
303 0
                        return (1);
304
                }
305
        }
306 21274
        return (0);
307
}
308
309
static void
310 21286
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
311
{
312
        struct proc *p;
313
        struct procuse *pu;
314
315 21286
        p = sym->proc;
316 21286
        AN(p);
317 21286
        if (p->method == NULL)
318 12
                return;
319 21274
        pu = vcc_FindIllegalUse(p, p->method);
320 21274
        if (pu != NULL) {
321 48
                VSB_printf(tl->sb, "'%.*s': %s in method '%.*s'.",
322 48
                    PF(pu->t), pu->use, PF(p->name));
323 12
                VSB_cat(tl->sb, "\nAt: ");
324 12
                vcc_ErrWhere(tl, pu->t);
325 12
                return;
326
        }
327 21262
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
328 0
                VSB_printf(tl->sb,
329 0
                    "\n...which is the \"%s\" method\n", p->method->name);
330 0
                return;
331
        }
332
}
333
334
int
335 1522
vcc_CheckUses(struct vcc *tl)
336
{
337
338 1522
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
339 1522
        return (tl->err);
340
}
341
342
/*---------------------------------------------------------------------*/
343
344
static void
345 386594
vcc_pnam(struct vcc *tl, const struct symbol *sym)
346
{
347
348 386594
        if (sym->parent != tl->symbols) {
349 185016
                vcc_pnam(tl, sym->parent);
350 185016
                Fc(tl, 0, ".");
351
        }
352 386594
        Fc(tl, 0, "%s", sym->name);
353 386594
}
354
355
static void v_matchproto_(symwalk_f)
356 201578
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
357
{
358
359 201578
        Fc(tl, 0, " * %-7s ", VCC_SymKind(tl, sym));
360 201578
        Fc(tl, 0, " %-9s ", sym->fmt != NULL ? sym->fmt->name : "");
361 201578
        vcc_pnam(tl, sym);
362 201578
        if (sym->wildcard != NULL)
363 9060
                Fc(tl, 0, "*");
364 201578
        Fc(tl, 0, "\n");
365 201578
}
366
367
void
368 1510
VCC_XrefTable(struct vcc *tl)
369
{
370
371 1510
        Fc(tl, 0, "\n/*\n * Symbol Table\n *\n");
372 1510
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_NONE);
373 1510
        Fc(tl, 0, "*/\n\n");
374 1510
}