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
        struct proc             *fm;
51
};
52
53
struct procuse {
54
        VTAILQ_ENTRY(procuse)   list;
55
        const struct token      *t1;
56
        const struct token      *t2;
57
        unsigned                mask;
58
        const char              *use;
59
        struct proc             *fm;
60
};
61
62
/*--------------------------------------------------------------------*/
63
64
static void
65 420939
vcc_checkref(struct vcc *tl, const struct symbol *sym)
66
{
67
68 420939
        if (sym->noref)
69 397677
                return;
70 23262
        if (sym->ndef == 0 && sym->nref != 0) {
71 3
                AN(sym->ref_b);
72 9
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
73 9
                    sym->kind->name, PF(sym->ref_b));
74 3
                vcc_ErrWhere(tl, sym->ref_b);
75 23259
        } else if (sym->ndef != 0 && sym->nref == 0) {
76 324
                AN(sym->def_b);
77 972
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
78 972
                    sym->kind->name, PF(sym->def_b));
79 324
                vcc_ErrWhere(tl, sym->def_b);
80 324
                if (!tl->err_unref) {
81 306
                        VSB_printf(tl->sb, "(That was just a warning)\n");
82 306
                        tl->err = 0;
83
                }
84
        }
85
}
86
87
int
88 2685
vcc_CheckReferences(struct vcc *tl)
89
{
90
91 2685
        VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
92 2685
        return (tl->err);
93
}
94
95
/*--------------------------------------------------------------------
96
 * Returns checks
97
 */
98
99
void
100 158292
vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
101
    unsigned mask, const char *use)
102
{
103
        struct procuse *pu;
104
105 158292
        if (tl->curproc == NULL)        /* backend */
106 0
                return;
107 158292
        pu = TlAlloc(tl, sizeof *pu);
108 158292
        assert(pu != NULL);
109 158292
        pu->t1 = t1;
110 158292
        pu->t2 = t2;
111 158292
        if (pu->t2 == NULL)
112 128334
                pu->t2 = VTAILQ_NEXT(t1, list);
113 158292
        pu->mask = mask;
114 158292
        pu->use = use;
115 158292
        pu->fm = tl->curproc;
116 158292
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
117
}
118
119
void
120 39
vcc_AddCall(struct vcc *tl, struct symbol *sym)
121
{
122
        struct proccall *pc;
123
124 39
        AN(sym);
125 39
        pc = TlAlloc(tl, sizeof *pc);
126 39
        assert(pc != NULL);
127 39
        pc->sym = sym;
128 39
        pc->t = tl->t;
129 39
        pc->fm = tl->curproc;
130 39
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
131 39
}
132
133
void
134 60108
vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
135
{
136
137 60108
        assert(returns < VCL_RET_MAX);
138 60108
        p->ret_bitmap |= (1U << returns);
139
        /* Record the first instance of this return */
140 60108
        if (p->return_tok[returns] == NULL)
141 48657
                p->return_tok[returns] = t;
142 60108
}
143
144
static int
145 37326
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
146
{
147
        unsigned u;
148
        struct proccall *pc;
149
150 37326
        AN(p);
151 37326
        if (p->active) {
152 6
                VSB_printf(tl->sb, "Function recurses on\n");
153 6
                vcc_ErrWhere(tl, p->name);
154 6
                return (1);
155
        }
156 37320
        u = p->ret_bitmap & ~bitmap;
157 37320
        if (u) {
158
159
#define VCL_RET_MAC(l, U, B)                                            \
160
                if (u & (1 << (VCL_RET_##U))) {                         \
161
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
162
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
163
                }
164
#include "tbl/vcl_returns.h"
165
166 6
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
167 6
                    PF(p->name));
168 3
                vcc_ErrWhere(tl, p->name);
169 3
                return (1);
170
        }
171 37317
        p->active = 1;
172 37338
        VTAILQ_FOREACH(pc, &p->calls, list) {
173 39
                if (pc->sym->proc == NULL) {
174 0
                        VSB_printf(tl->sb, "Function %s does not exist\n",
175 0
                            pc->sym->name);
176 0
                        vcc_ErrWhere(tl, pc->t);
177 0
                        return (1);
178
                }
179 39
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
180 18
                        VSB_printf(tl->sb, "\n...called from \"%s\"\n",
181 18
                            pc->sym->name);
182 18
                        vcc_ErrWhere(tl, pc->t);
183 18
                        return (1);
184
                }
185
        }
186 37299
        p->active = 0;
187 37299
        p->called++;
188 37299
        return (0);
189
}
190
191
/*--------------------------------------------------------------------*/
192
193
static void
194 37320
vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
195
{
196
        struct proc *p;
197
198 37320
        p = sym->proc;
199 37320
        AN(p);
200 37320
        AN(p->name);
201 37320
        if (p->method == NULL)
202 33
                return;
203 37287
        if (vcc_CheckActionRecurse(tl, p, p->method->ret_bitmap)) {
204 9
                VSB_printf(tl->sb,
205 9
                    "\n...which is the \"%s\" method\n", p->method->name);
206 9
                VSB_printf(tl->sb, "Legal returns are:");
207
#define VCL_RET_MAC(l, U, B)                                            \
208
                if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))       \
209
                        VSB_printf(tl->sb, " \"%s\"", #l);
210
211
#include "tbl/vcl_returns.h"
212 9
                VSB_printf(tl->sb, "\n");
213 9
                tl->err = 1;
214
        }
215
216
}
217
218
static void
219 37191
vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
220
{
221
        struct proc *p;
222
223 37191
        p = sym->proc;
224 37191
        AN(p);
225
226 37191
        if (p->called)
227 37188
                return;
228 3
        VSB_printf(tl->sb, "Function unused\n");
229 3
        vcc_ErrWhere(tl, p->name);
230 3
        if (!tl->err_unref) {
231 3
                VSB_printf(tl->sb, "(That was just a warning)\n");
232 3
                tl->err = 0;
233
        }
234
}
235
236
int
237 2664
vcc_CheckAction(struct vcc *tl)
238
{
239
240 2664
        VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
241 2664
        if (tl->err)
242 9
                return (tl->err);
243 2655
        VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
244 2655
        return (tl->err);
245
}
246
247
/*--------------------------------------------------------------------*/
248
249
static struct procuse *
250 74241
vcc_FindIllegalUse(const struct proc *p, const struct method *m)
251
{
252
        struct procuse *pu;
253
254 385977
        VTAILQ_FOREACH(pu, &p->uses, list)
255 311754
                if (!(pu->mask & m->bitval))
256 18
                        return (pu);
257 74223
        return (NULL);
258
}
259
260
static int
261 37122
vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
262
    const struct method *m)
263
{
264
        struct proccall *pc;
265
        struct procuse *pu;
266
267 37122
        pu = vcc_FindIllegalUse(p, m);
268 37122
        if (pu != NULL) {
269 0
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
270 0
                VSB_printf(tl->sb, "%s from method '%s'.\n",
271
                    pu->use, m->name);
272 0
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
273 0
                    PF(pu->fm->name));
274 0
                vcc_ErrWhere(tl, p->name);
275 0
                return (1);
276
        }
277 37143
        VTAILQ_FOREACH(pc, &p->calls, list) {
278 21
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
279 0
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
280 0
                            PF(pc->fm->name));
281 0
                        vcc_ErrWhere(tl, pc->t);
282 0
                        return (1);
283
                }
284
        }
285 37122
        return (0);
286
}
287
288
static void
289 37140
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
290
{
291
        struct proc *p;
292
        struct procuse *pu;
293
294 37140
        p = sym->proc;
295 37140
        AN(p);
296 37140
        if (p->method == NULL)
297 21
                return;
298 37119
        pu = vcc_FindIllegalUse(p, p->method);
299 37119
        if (pu != NULL) {
300 18
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
301 36
                VSB_printf(tl->sb, "%s in method '%.*s'.",
302 36
                    pu->use, PF(p->name));
303 18
                VSB_cat(tl->sb, "\nAt: ");
304 18
                return;
305
        }
306 37101
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
307 0
                VSB_printf(tl->sb,
308 0
                    "\n...which is the \"%s\" method\n", p->method->name);
309 0
                return;
310
        }
311
}
312
313
int
314 2655
vcc_CheckUses(struct vcc *tl)
315
{
316
317 2655
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
318 2655
        return (tl->err);
319
}
320
321
/*---------------------------------------------------------------------*/
322
323
static void
324 757137
vcc_pnam(struct vcc *tl, const struct symbol *sym)
325
{
326
327 757137
        if (sym->parent != tl->symbols) {
328 341424
                vcc_pnam(tl, sym->parent);
329 341424
                Fc(tl, 0, ".");
330
        }
331 757137
        Fc(tl, 0, "%s", sym->name);
332 757137
}
333
334
static void v_matchproto_(symwalk_f)
335 415713
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
336
{
337
338 415713
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
339 415713
        CHECK_OBJ_NOTNULL(sym->kind, KIND_MAGIC);
340 415713
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
341 415713
        Fc(tl, 0, " * %-8s ", sym->kind->name);
342 415713
        Fc(tl, 0, " %-9s ", sym->type->name);
343 415713
        Fc(tl, 0, " %2u %2u ", sym->lorev, sym->hirev);
344 415713
        vcc_pnam(tl, sym);
345 415713
        if (sym->wildcard != NULL)
346 16773
                Fc(tl, 0, "*");
347 415713
        Fc(tl, 0, "\n");
348 415713
}
349
350
void
351 2637
VCC_XrefTable(struct vcc *tl)
352
{
353
354 2637
        Fc(tl, 0, "\n/*\n * Symbol Table\n *\n");
355 2637
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_NONE);
356 2637
        Fc(tl, 0, "*/\n\n");
357 2637
}