varnish-cache/bin/varnishd/cache/cache_panic.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dag-Erling Smørgrav <des@des.no>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * 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
 *    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
 * 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
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32 6
33 6
#include <stdio.h>
34 20
#include <stdlib.h>
35 20
#include <signal.h>
36 19
37 13
#include "cache_varnishd.h"
38 10
#include "cache_transport.h"
39 7
40 7
#include "cache_filter.h"
41 7
#include "common/heritage.h"
42 6
#include "waiter/waiter.h"
43 6
44 6
#include "storage/storage.h"
45
#include "vcli_serve.h"
46
#include "vtim.h"
47
#include "vbt.h"
48
#include "vcs.h"
49
#include "vtcp.h"
50
#include "vsa.h"
51
52
/*
53
 * The panic string is constructed in a VSB, then copied to the
54
 * shared memory.
55
 *
56
 * It can be extracted post-mortem from a core dump using gdb:
57
 *
58
 * (gdb) p *(char **)((char *)pan_vsb+8)
59
 *
60
 */
61
62
static struct vsb pan_vsb_storage, *pan_vsb;
63
static pthread_mutex_t panicstr_mtx;
64
65
static void pan_sess(struct vsb *, const struct sess *);
66
static void pan_req(struct vsb *, const struct req *);
67
68
/*--------------------------------------------------------------------*/
69
70
static const char *
71 1
boc_state_2str(enum boc_state_e e)
72
{
73 1
        switch (e) {
74
#define BOC_STATE(U,l) case BOS_##U: return(#l);
75
#include "tbl/boc_state.h"
76
        default:
77
                return ("?");
78
        }
79 1
}
80
81
/*--------------------------------------------------------------------*/
82
83
static void
84 7
pan_stream_close(struct vsb *vsb, stream_close_t sc)
85
{
86
87 7
        if (sc != NULL && sc->magic == STREAM_CLOSE_MAGIC)
88 7
                VSB_printf(vsb, "%s(%s)", sc->name, sc->desc);
89
        else
90 0
                VSB_printf(vsb, "%p", sc);
91 7
}
92
93
/*--------------------------------------------------------------------*/
94
95
static void
96 7
pan_storage(struct vsb *vsb, const char *n, const struct stevedore *stv)
97
{
98
99 7
        if (stv != NULL && stv->magic == STEVEDORE_MAGIC)
100 2
                VSB_printf(vsb, "%s = %s(%s,%s),\n",
101 1
                    n, stv->name, stv->ident, stv->vclname);
102
        else
103 6
                VSB_printf(vsb, "%s = %p,\n", n, stv);
104 7
}
105
106
/*--------------------------------------------------------------------*/
107
108
#define N_ALREADY 256
109
static const void *already_list[N_ALREADY];
110
static int already_idx;
111
112
int
113 206
PAN__DumpStruct(struct vsb *vsb, int block, int track, const void *ptr,
114
    const char *smagic, unsigned magic, const char *fmt, ...)
115
{
116
        va_list ap;
117
        const unsigned *uptr;
118
        int i;
119
120 206
        AN(vsb);
121 206
        va_start(ap, fmt);
122 206
        VSB_vprintf(vsb, fmt, ap);
123 206
        va_end(ap);
124 206
        if (ptr == NULL) {
125 31
                VSB_cat(vsb, " = NULL\n");
126 31
                return (-1);
127
        }
128 175
        VSB_printf(vsb, " = %p {", ptr);
129 175
        if (block)
130 172
                VSB_putc(vsb, '\n');
131 175
        if (track) {
132 1591
                for (i = 0; i < already_idx; i++) {
133 1445
                        if (already_list[i] == ptr) {
134 29
                                VSB_cat(vsb, "  [Already dumped, see above]");
135 29
                                if (block)
136 29
                                        VSB_putc(vsb, '\n');
137 29
                                VSB_cat(vsb, "},\n");
138 29
                                return (-2);
139
                        }
140 1416
                }
141 146
                if (already_idx < N_ALREADY)
142 146
                        already_list[already_idx++] = ptr;
143 146
        }
144 146
        uptr = ptr;
145 146
        if (*uptr != magic) {
146 4
                VSB_printf(vsb, "  .magic = 0x%08x", *uptr);
147 4
                VSB_printf(vsb, " EXPECTED: %s=0x%08x", smagic, magic);
148 4
                if (block)
149 4
                        VSB_putc(vsb, '\n');
150 4
                VSB_cat(vsb, "}\n");
151 4
                return (-3);
152
        }
153 142
        if (block)
154 139
                VSB_indent(vsb, 2);
155 142
        return (0);
156 206
}
157
158
/*--------------------------------------------------------------------*/
159
160
static void
161 7
pan_htc(struct vsb *vsb, const struct http_conn *htc)
162
{
163
164 7
        if (PAN_dump_struct(vsb, htc, HTTP_CONN_MAGIC, "http_conn"))
165 0
                return;
166 7
        if (htc->rfd != NULL)
167 6
                VSB_printf(vsb, "fd = %d (@%p),\n", *htc->rfd, htc->rfd);
168 7
        VSB_cat(vsb, "doclose = ");
169 7
        pan_stream_close(vsb, htc->doclose);
170 7
        VSB_cat(vsb, "\n");
171 7
        WS_Panic(vsb, htc->ws);
172 14
        VSB_printf(vsb, "{rxbuf_b, rxbuf_e} = {%p, %p},\n",
173 7
            htc->rxbuf_b, htc->rxbuf_e);
174 14
        VSB_printf(vsb, "{pipeline_b, pipeline_e} = {%p, %p},\n",
175 7
            htc->pipeline_b, htc->pipeline_e);
176 14
        VSB_printf(vsb, "content_length = %jd,\n",
177 7
            (intmax_t)htc->content_length);
178 14
        VSB_printf(vsb, "body_status = %s,\n",
179 7
            htc->body_status ? htc->body_status->name : "NULL");
180 14
        VSB_printf(vsb, "first_byte_timeout = %f,\n",
181 7
            htc->first_byte_timeout);
182 14
        VSB_printf(vsb, "between_bytes_timeout = %f,\n",
183 7
            htc->between_bytes_timeout);
184 7
        VSB_indent(vsb, -2);
185 7
        VSB_cat(vsb, "},\n");
186 7
}
187
188
/*--------------------------------------------------------------------*/
189
190
static void
191 10
pan_http(struct vsb *vsb, const char *id, const struct http *h)
192
{
193
        int i;
194
195 10
        if (PAN_dump_struct(vsb, h, HTTP_MAGIC, "http[%s]", id))
196 0
                return;
197 10
        WS_Panic(vsb, h->ws);
198 10
        VSB_cat(vsb, "hdrs {\n");
199 10
        VSB_indent(vsb, 2);
200 114
        for (i = 0; i < h->nhd; ++i) {
201 104
                if (h->hd[i].b == NULL && h->hd[i].e == NULL)
202 20
                        continue;
203 168
                VSB_printf(vsb, "\"%.*s\",\n",
204 84
                    (int)(h->hd[i].e - h->hd[i].b), h->hd[i].b);
205 84
        }
206 10
        VSB_indent(vsb, -2);
207 10
        VSB_cat(vsb, "},\n");
208 10
        VSB_indent(vsb, -2);
209 10
        VSB_cat(vsb, "},\n");
210 10
}
211
212
/*--------------------------------------------------------------------*/
213
214
static void
215 1
pan_boc(struct vsb *vsb, const struct boc *boc)
216
{
217 1
        if (PAN_dump_struct(vsb, boc, BOC_MAGIC, "boc"))
218 0
                return;
219 1
        VSB_printf(vsb, "refcnt = %u,\n", boc->refcount);
220 1
        VSB_printf(vsb, "state = %s,\n", boc_state_2str(boc->state));
221 1
        VSB_printf(vsb, "vary = %p,\n", boc->vary);
222 1
        VSB_printf(vsb, "stevedore_priv = %p,\n", boc->stevedore_priv);
223 1
        VSB_indent(vsb, -2);
224 1
        VSB_cat(vsb, "},\n");
225 1
}
226
227
/*--------------------------------------------------------------------*/
228
229
static void
230 3
pan_objcore(struct vsb *vsb, const char *typ, const struct objcore *oc)
231
{
232
        const char *p;
233
234 3
        if (PAN_dump_struct(vsb, oc, OBJCORE_MAGIC, "objcore[%s]", typ))
235 0
                return;
236 3
        VSB_printf(vsb, "refcnt = %d,\n", oc->refcnt);
237 3
        VSB_cat(vsb, "flags = {");
238
239
/*lint -save -esym(438,p) -esym(838,p) -e539 */
240 3
        p = "";
241
#define OC_FLAG(U, l, v) \
242
        if (oc->flags & v) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
243
#include "tbl/oc_flags.h"
244
        VSB_cat(vsb, "},\n");
245
        VSB_cat(vsb, "exp_flags = {");
246
        p = "";
247
#define OC_EXP_FLAG(U, l, v) \
248
        if (oc->exp_flags & v) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
249
#include "tbl/oc_exp_flags.h"
250
/*lint -restore */
251
        VSB_cat(vsb, "},\n");
252
253 3
        if (oc->boc != NULL)
254 1
                pan_boc(vsb, oc->boc);
255
        VSB_printf(vsb, "exp = {%f, %f, %f, %f},\n",
256
            oc->t_origin, oc->ttl, oc->grace, oc->keep);
257
        VSB_printf(vsb, "objhead = %p,\n", oc->objhead);
258
        VSB_printf(vsb, "stevedore = %p", oc->stobj->stevedore);
259 3
        if (oc->stobj->stevedore != NULL) {
260 2
                VSB_printf(vsb, " (%s", oc->stobj->stevedore->name);
261 2
                if (strlen(oc->stobj->stevedore->ident))
262 2
                        VSB_printf(vsb, " %s", oc->stobj->stevedore->ident);
263 2
                VSB_cat(vsb, ")");
264 2
                if (oc->stobj->stevedore->panic) {
265 2
                        VSB_cat(vsb, " {\n");
266 2
                        VSB_indent(vsb, 2);
267 2
                        oc->stobj->stevedore->panic(vsb, oc);
268 2
                        VSB_indent(vsb, -2);
269 2
                        VSB_cat(vsb, "}");
270 2
                }
271 2
        }
272
        VSB_cat(vsb, ",\n");
273
        VSB_indent(vsb, -2);
274
        VSB_cat(vsb, "},\n");
275
}
276
277
/*--------------------------------------------------------------------*/
278
279
static void
280 19
pan_wrk(struct vsb *vsb, const struct worker *wrk)
281
{
282
        const char *hand;
283
        unsigned m, u;
284
        const char *p;
285
286 19
        if (PAN_dump_struct(vsb, wrk, WORKER_MAGIC, "worker"))
287 12
                return;
288 7
        WS_Panic(vsb, wrk->aws);
289
290 7
        m = wrk->cur_method;
291 7
        VSB_cat(vsb, "VCL::method = ");
292 7
        if (m == 0) {
293 0
                VSB_cat(vsb, "none,\n");
294 0
                return;
295
        }
296 7
        if (!(m & 1))
297 6
                VSB_cat(vsb, "inside ");
298 7
        m &= ~1;
299 7
        hand = VCL_Method_Name(m);
300 7
        if (hand != NULL)
301 7
                VSB_printf(vsb, "%s,\n", hand);
302
        else
303 0
                VSB_printf(vsb, "0x%x,\n", m);
304
305 7
        VSB_cat(vsb, "VCL::methods = {");
306 7
        m = wrk->seen_methods;
307 7
        p = "";
308 45
        for (u = 1; m ; u <<= 1) {
309 38
                if (m & u) {
310 14
                        VSB_printf(vsb, "%s%s", p, VCL_Method_Name(u));
311 14
                        m &= ~u;
312 14
                        p = ", ";
313 14
                }
314 38
        }
315 7
        VSB_cat(vsb, "},\n");
316 7
        VSB_indent(vsb, -2);
317 7
        VSB_cat(vsb, "},\n");
318 19
}
319
320
static void
321 1
pan_vfp(struct vsb *vsb, const struct vfp_ctx *vfc)
322
{
323
        struct vfp_entry *vfe;
324
325 1
        if (PAN_dump_struct(vsb, vfc, VFP_CTX_MAGIC, "vfc"))
326 0
                return;
327 1
        VSB_printf(vsb, "failed = %d,\n", vfc->failed);
328 1
        VSB_printf(vsb, "req = %p,\n", vfc->req);
329 1
        VSB_printf(vsb, "resp = %p,\n", vfc->resp);
330 1
        VSB_printf(vsb, "wrk = %p,\n", vfc->wrk);
331 1
        VSB_printf(vsb, "oc = %p,\n", vfc->oc);
332
333 1
        if (!VTAILQ_EMPTY(&vfc->vfp)) {
334 1
                VSB_cat(vsb, "filters = {\n");
335 1
                VSB_indent(vsb, 2);
336 2
                VTAILQ_FOREACH(vfe, &vfc->vfp, list) {
337 1
                        VSB_printf(vsb, "%s = %p {\n", vfe->vfp->name, vfe);
338 1
                        VSB_indent(vsb, 2);
339 1
                        VSB_printf(vsb, "priv1 = %p,\n", vfe->priv1);
340 1
                        VSB_printf(vsb, "priv2 = %zd,\n", vfe->priv2);
341 1
                        VSB_printf(vsb, "closed = %d\n", vfe->closed);
342 1
                        VSB_indent(vsb, -2);
343 1
                        VSB_cat(vsb, "},\n");
344 1
                }
345 1
                VSB_indent(vsb, -2);
346 1
                VSB_cat(vsb, "},\n");
347 1
        }
348
349 1
        VSB_printf(vsb, "obj_flags = 0x%x,\n", vfc->obj_flags);
350 1
        VSB_indent(vsb, -2);
351 1
        VSB_cat(vsb, "},\n");
352 1
}
353
354
static void
355 12
pan_busyobj(struct vsb *vsb, const struct busyobj *bo)
356
{
357
        const char *p;
358
        const struct worker *wrk;
359
360 12
        if (PAN_dump_struct(vsb, bo, BUSYOBJ_MAGIC, "busyobj"))
361 11
                return;
362 1
        VSB_printf(vsb, "end = %p,\n", bo->end);
363 1
        VSB_printf(vsb, "retries = %u,\n", bo->retries);
364
365 1
        if (bo->req != NULL)
366 0
                pan_req(vsb, bo->req);
367 1
        if (bo->sp != NULL)
368 1
                pan_sess(vsb, bo->sp);
369 1
        wrk = bo->wrk;
370 1
        if (wrk != NULL)
371 1
                pan_wrk(vsb, wrk);
372
373 1
        if (bo->vfc != NULL)
374 1
                pan_vfp(vsb, bo->vfc);
375 1
        if (bo->vfp_filter_list != NULL) {
376 0
                VSB_printf(vsb, "vfp_filter_list = \"%s\",\n",
377 0
                    bo->vfp_filter_list);
378 0
        }
379 1
        if (bo->vdp_filter_list != NULL) {
380 0
                VSB_printf(vsb, "vdp_filter_list = \"%s\",\n",
381 0
                    bo->vdp_filter_list);
382 0
        }
383
384 1
        WS_Panic(vsb, bo->ws);
385 1
        VSB_printf(vsb, "ws_bo = %p,\n", (void *)bo->ws_bo);
386
387
        // bereq0 left out
388 1
        if (bo->bereq != NULL && bo->bereq->ws != NULL)
389 1
                pan_http(vsb, "bereq", bo->bereq);
390 1
        if (bo->beresp != NULL && bo->beresp->ws != NULL)
391 1
                pan_http(vsb, "beresp", bo->beresp);
392 1
        if (bo->stale_oc)
393 0
                pan_objcore(vsb, "stale_oc", bo->stale_oc);
394 1
        if (bo->fetch_objcore)
395 1
                pan_objcore(vsb, "fetch", bo->fetch_objcore);
396
397 1
        if (VALID_OBJ(bo->htc, HTTP_CONN_MAGIC))
398 1
                pan_htc(vsb, bo->htc);
399
400
        // fetch_task left out
401
402 1
        VSB_cat(vsb, "flags = {");
403 1
        p = "";
404
/*lint -save -esym(438,p) -e539 */
405
#define BERESP_FLAG(l, r, w, f, d)                              \
406
        if (bo->l) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
407
#define BEREQ_FLAG(l, r, w, d) BERESP_FLAG(l, r, w, 0, d)
408
#include "tbl/bereq_flags.h"
409
#include "tbl/beresp_flags.h"
410
/*lint -restore */
411
        VSB_cat(vsb, "},\n");
412
413
        // timeouts/timers/acct/storage left out
414
415
        pan_storage(vsb, "storage", bo->storage);
416
        VDI_Panic(bo->director_req, vsb, "director_req");
417 1
        if (bo->director_resp == bo->director_req)
418 1
                VSB_cat(vsb, "director_resp = director_req,\n");
419
        else
420 0
                VDI_Panic(bo->director_resp, vsb, "director_resp");
421
        VCL_Panic(vsb, "vcl", bo->vcl);
422 1
        if (wrk != NULL)
423 1
                VPI_Panic(vsb, wrk->vpi, bo->vcl);
424
425
        VSB_indent(vsb, -2);
426
        VSB_cat(vsb, "},\n");
427
}
428
429
/*--------------------------------------------------------------------*/
430
431
static void
432 6
pan_top(struct vsb *vsb, const struct reqtop *top)
433
{
434 6
        if (PAN_dump_struct(vsb, top, REQTOP_MAGIC, "top"))
435 0
                return;
436 6
        pan_req(vsb, top->topreq);
437 6
        pan_privs(vsb, top->privs);
438 6
        VCL_Panic(vsb, "vcl0", top->vcl0);
439 6
        VSB_indent(vsb, -2);
440 6
        VSB_cat(vsb, "},\n");
441 6
}
442
443
/*--------------------------------------------------------------------*/
444
445
static void
446 18
pan_req(struct vsb *vsb, const struct req *req)
447
{
448
        const struct transport *xp;
449
        const struct worker *wrk;
450
451 18
        if (PAN_dump_struct(vsb, req, REQ_MAGIC, "req"))
452 12
                return;
453 6
        xp = req->transport;
454 12
        VSB_printf(vsb, "vxid = %ju, transport = %s", VXID(req->vsl->wid),
455 6
            xp == NULL ? "NULL" : xp->name);
456
457 6
        if (xp != NULL && xp->req_panic != NULL) {
458 5
                VSB_cat(vsb, " {\n");
459 5
                VSB_indent(vsb, 2);
460 5
                xp->req_panic(vsb, req);
461 5
                VSB_indent(vsb, -2);
462 5
                VSB_cat(vsb, "}");
463 5
        }
464 6
        VSB_cat(vsb, "\n");
465 6
        if (req->req_step == NULL)
466 0
                VSB_cat(vsb, "step = R_STP_TRANSPORT\n");
467
        else
468 6
                VSB_printf(vsb, "step = %s\n", req->req_step->name);
469
470 6
        if (req->vfp_filter_list != NULL) {
471 0
                VSB_printf(vsb, "vfp_filter_list = \"%s\",\n",
472 0
                    req->vfp_filter_list);
473 0
        }
474 6
        if (req->vdp_filter_list != NULL) {
475 2
                VSB_printf(vsb, "vdp_filter_list = \"%s\",\n",
476 1
                    req->vdp_filter_list);
477 1
        }
478
479 12
        VSB_printf(vsb, "req_body = %s,\n",
480 6
            req->req_body_status ? req->req_body_status->name : "NULL");
481
482 6
        if (req->err_code)
483 0
                VSB_printf(vsb,
484 0
                    "err_code = %d, err_reason = %s,\n", req->err_code,
485 0
                    req->err_reason ? req->err_reason : "(null)");
486
487 12
        VSB_printf(vsb, "restarts = %u, esi_level = %u,\n",
488 6
            req->restarts, req->esi_level);
489
490 12
        VSB_printf(vsb, "vary_b = %p, vary_e = %p,\n",
491 6
            req->vary_b, req->vary_e);
492
493 12
        VSB_printf(vsb, "d_ttl = %f, d_grace = %f,\n",
494 6
            req->d_ttl, req->d_grace);
495
496 6
        pan_storage(vsb, "storage", req->storage);
497
498 6
        VDI_Panic(req->director_hint, vsb, "director_hint");
499
500 6
        if (req->sp != NULL)
501 6
                pan_sess(vsb, req->sp);
502
503 6
        wrk = req->wrk;
504 6
        if (wrk != NULL)
505 6
                pan_wrk(vsb, wrk);
506
507 6
        WS_Panic(vsb, req->ws);
508 6
        if (VALID_OBJ(req->htc, HTTP_CONN_MAGIC))
509 6
                pan_htc(vsb, req->htc);
510 6
        pan_http(vsb, "req", req->http);
511 6
        if (req->resp != NULL && req->resp->ws != NULL)
512 2
                pan_http(vsb, "resp", req->resp);
513 6
        if (req->vdc != NULL)
514 6
                VDP_Panic(vsb, req->vdc);
515
516 6
        VCL_Panic(vsb, "vcl", req->vcl);
517 6
        if (wrk != NULL)
518 6
                VPI_Panic(vsb, wrk->vpi, req->vcl);
519
520 6
        if (req->body_oc != NULL)
521 0
                pan_objcore(vsb, "BODY", req->body_oc);
522 6
        if (req->objcore != NULL)
523 2
                pan_objcore(vsb, "REQ", req->objcore);
524
525 6
        VSB_cat(vsb, "flags = {\n");
526 6
        VSB_indent(vsb, 2);
527
#define REQ_FLAG(l, r, w, d) if (req->l) VSB_printf(vsb, #l ",\n");
528
#include "tbl/req_flags.h"
529
        VSB_indent(vsb, -2);
530
        VSB_cat(vsb, "},\n");
531
532
        pan_privs(vsb, req->privs);
533
534 6
        if (req->top != NULL)
535 6
                pan_top(vsb, req->top);
536
537
        VSB_indent(vsb, -2);
538
        VSB_cat(vsb, "},\n");
539
}
540
541
/*--------------------------------------------------------------------*/
542
543
#define pan_addr(vsb, sp, field) do {                                   \
544
                struct suckaddr *sa;                                    \
545
                char h[VTCP_ADDRBUFSIZE];                               \
546
                char p[VTCP_PORTBUFSIZE];                               \
547
                                                                        \
548
                (void) SES_Get_##field##_addr((sp), &sa);               \
549
                if (! VSA_Sane(sa))                                     \
550
                        break;                                          \
551
                VTCP_name(sa, h, sizeof h, p, sizeof p);                \
552
                VSB_printf((vsb), "%s.ip = %s:%s,\n", #field, h, p);    \
553
        } while (0)
554
555
static void
556 7
pan_sess(struct vsb *vsb, const struct sess *sp)
557
{
558
        const char *ci;
559
        const char *cp;
560
        const struct transport *xp;
561
562 7
        if (PAN_dump_struct(vsb, sp, SESS_MAGIC, "sess"))
563 0
                return;
564 14
        VSB_printf(vsb, "fd = %d, vxid = %ju,\n",
565 7
            sp->fd, VXID(sp->vxid));
566 7
        VSB_printf(vsb, "t_open = %f,\n", sp->t_open);
567 7
        VSB_printf(vsb, "t_idle = %f,\n", sp->t_idle);
568
569 7
        if (! VALID_OBJ(sp, SESS_MAGIC)) {
570 0
                VSB_indent(vsb, -2);
571 0
                VSB_cat(vsb, "},\n");
572 0
                return;
573
        }
574
575 7
        WS_Panic(vsb, sp->ws);
576 7
        xp = XPORT_ByNumber(sp->sattr[SA_TRANSPORT]);
577 14
        VSB_printf(vsb, "transport = %s",
578 7
            xp == NULL ? "<none>" : xp->name);
579 7
        if (xp != NULL && xp->sess_panic != NULL) {
580 7
                VSB_cat(vsb, " {\n");
581 7
                VSB_indent(vsb, 2);
582 7
                xp->sess_panic(vsb, sp);
583 7
                VSB_indent(vsb, -2);
584 7
                VSB_cat(vsb, "}");
585 7
        }
586 7
        VSB_cat(vsb, "\n");
587
588
        // duplicated below, remove ?
589 7
        ci = SES_Get_String_Attr(sp, SA_CLIENT_IP);
590 7
        cp = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
591 7
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC))
592 14
                VSB_printf(vsb, "client = %s %s %s,\n", ci, cp,
593 7
                           sp->listen_sock->endpoint);
594
        else
595 0
                VSB_printf(vsb, "client = %s %s <unknown>\n", ci, cp);
596
597 7
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC)) {
598 14
                VSB_printf(vsb, "local.endpoint = %s,\n",
599 7
                           sp->listen_sock->endpoint);
600 14
                VSB_printf(vsb, "local.socket = %s,\n",
601 7
                           sp->listen_sock->name);
602 7
        }
603 7
        pan_addr(vsb, sp, local);
604 7
        pan_addr(vsb, sp, remote);
605 7
        pan_addr(vsb, sp, server);
606 7
        pan_addr(vsb, sp, client);
607
608 7
        VSB_indent(vsb, -2);
609 7
        VSB_cat(vsb, "},\n");
610 7
}
611
612
/*--------------------------------------------------------------------*/
613
614
static void
615 12
pan_backtrace(struct vsb *vsb)
616
{
617
618 12
        VSB_cat(vsb, "Backtrace:\n");
619 12
        VSB_indent(vsb, 2);
620 12
        VBT_format(vsb);
621 12
        VSB_indent(vsb, -2);
622 12
}
623
624
#ifdef HAVE_PTHREAD_GETATTR_NP
625
static void
626
pan_threadattr(struct vsb *vsb)
627
{
628
        pthread_attr_t attr[1];
629
        size_t sz;
630
        void *addr;
631
632
        if (pthread_getattr_np(pthread_self(), attr) != 0)
633
                return;
634
635
        VSB_cat(vsb, "pthread.attr = {\n");
636
        VSB_indent(vsb, 2);
637
638
        if (pthread_attr_getguardsize(attr, &sz) == 0)
639
                VSB_printf(vsb, "guard = %zu,\n", sz);
640
        if (pthread_attr_getstack(attr, &addr, &sz) == 0) {
641
                VSB_printf(vsb, "stack_bottom = %p,\n", addr);
642
                VSB_printf(vsb, "stack_top = %p,\n", (char *)addr + sz);
643
                VSB_printf(vsb, "stack_size = %zu,\n", sz);
644
        }
645
        VSB_indent(vsb, -2);
646
        VSB_cat(vsb, "}\n");
647
        (void) pthread_attr_destroy(attr);
648
}
649
#endif
650
651
static void
652 12
pan_argv(struct vsb *vsb)
653
{
654
        int i;
655
656 12
        VSB_cat(pan_vsb, "argv = {\n");
657 12
        VSB_indent(vsb, 2);
658 381
        for (i = 0; i < heritage.argc; i++) {
659 369
                VSB_printf(vsb, "[%d] = ", i);
660 369
                VSB_quote(vsb, heritage.argv[i], -1, VSB_QUOTE_CSTR);
661 369
                VSB_cat(vsb, ",\n");
662 369
        }
663 12
        VSB_indent(vsb, -2);
664 12
        VSB_cat(vsb, "}\n");
665
666 12
}
667
/*--------------------------------------------------------------------*/
668
669
static void __attribute__((__noreturn__))
670 12
pan_ic(const char *func, const char *file, int line, const char *cond,
671
    enum vas_e kind)
672
{
673
        const char *q;
674
        struct req *req;
675
        struct busyobj *bo;
676
        struct worker *wrk;
677
        struct sigaction sa;
678 12
        int i, err = errno;
679
680 12
        if (pthread_getspecific(panic_key) != NULL) {
681 0
                VSB_cat(pan_vsb, "\n\nPANIC REENTRANCY\n\n");
682 0
                abort();
683
        }
684
685
        /* If we already panicking in another thread, do nothing */
686 12
        do {
687 12
                i = pthread_mutex_trylock(&panicstr_mtx);
688 12
                if (i != 0)
689 0
                        sleep (1);
690 12
        } while (i != 0);
691
692 12
        assert (VSB_len(pan_vsb) == 0);
693
694 12
        AZ(pthread_setspecific(panic_key, pan_vsb));
695
696
        /*
697
         * should we trigger a SIGSEGV while handling a panic, our sigsegv
698
         * handler would hide the panic, so we need to reset the handler to
699
         * default
700
         */
701 12
        memset(&sa, 0, sizeof sa);
702 12
        sa.sa_handler = SIG_DFL;
703 12
        (void)sigaction(SIGSEGV, &sa, NULL);
704
        /* Set SIGABRT back to default so the final abort() has the
705
           desired effect */
706 12
        (void)sigaction(SIGABRT, &sa, NULL);
707
708 12
        switch (kind) {
709
        case VAS_WRONG:
710 12
                VSB_printf(pan_vsb,
711 6
                    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
712 6
                break;
713
        case VAS_VCL:
714 6
                VSB_printf(pan_vsb,
715 3
                    "Panic from VCL:\n  %s\n", cond);
716 3
                break;
717
        case VAS_MISSING:
718 0
                VSB_printf(pan_vsb,
719
                    "Missing error handling code in %s(), %s line %d:\n"
720
                    "  Condition(%s) not true.\n",
721 0
                    func, file, line, cond);
722 0
                break;
723
        case VAS_INCOMPLETE:
724 0
                VSB_printf(pan_vsb,
725
                    "Incomplete code in %s(), %s line %d:\n",
726 0
                    func, file, line);
727 0
                break;
728 3
        case VAS_ASSERT:
729
        default:
730 6
                VSB_printf(pan_vsb,
731
                    "Assert error in %s(), %s line %d:\n"
732
                    "  Condition(%s) not true.\n",
733 3
                    func, file, line, cond);
734 3
                break;
735
        }
736 24
        VSB_printf(pan_vsb, "version = %s, vrt api = %u.%u\n",
737 12
            VCS_String("V"), VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
738 24
        VSB_printf(pan_vsb, "ident = %s,%s\n",
739 12
            heritage.ident, Waiter_GetName());
740 24
        VSB_printf(pan_vsb, "now = %f (mono), %f (real)\n",
741 12
            VTIM_mono(), VTIM_real());
742
743 12
        pan_backtrace(pan_vsb);
744
745 12
        if (err)
746 1
                VSB_printf(pan_vsb, "errno = %d (%s)\n", err, VAS_errtxt(err));
747
748 12
        pan_argv(pan_vsb);
749
750 12
        VSB_printf(pan_vsb, "pthread.self = %p\n", TRUST_ME(pthread_self()));
751
752 12
        q = THR_GetName();
753 12
        if (q != NULL)
754 12
                VSB_printf(pan_vsb, "pthread.name = (%s)\n", q);
755
756
#ifdef HAVE_PTHREAD_GETATTR_NP
757
        pan_threadattr(pan_vsb);
758
#endif
759
760 12
        if (!FEATURE(FEATURE_SHORT_PANIC)) {
761 12
                req = THR_GetRequest();
762 12
                VSB_cat(pan_vsb, "thr.");
763 12
                pan_req(pan_vsb, req);
764 12
                if (req != NULL)
765 6
                        VSL_Flush(req->vsl, 0);
766 12
                bo = THR_GetBusyobj();
767 12
                VSB_cat(pan_vsb, "thr.");
768 12
                pan_busyobj(pan_vsb, bo);
769 12
                if (bo != NULL)
770 1
                        VSL_Flush(bo->vsl, 0);
771 12
                wrk = THR_GetWorker();
772 12
                VSB_cat(pan_vsb, "thr.");
773 12
                pan_wrk(pan_vsb, wrk);
774 12
                VMOD_Panic(pan_vsb);
775 12
                pan_pool(pan_vsb);
776 12
        } else {
777 0
                VSB_cat(pan_vsb, "Feature short panic suppressed details.\n");
778
        }
779 12
        VSB_cat(pan_vsb, "\n");
780 12
        VSB_putc(pan_vsb, '\0');        /* NUL termination */
781
782 12
        v_gcov_flush();
783
784
        /*
785
         * Do a little song and dance for static checkers which
786
         * are not smart enough to figure out that calling abort()
787
         * with a mutex held is OK and probably very intentional.
788
         */
789 12
        if (pthread_getspecific(panic_key))     /* ie: always */
790 12
                abort();
791 0
        PTOK(pthread_mutex_unlock(&panicstr_mtx));
792 0
        abort();
793
}
794
795
/*--------------------------------------------------------------------*/
796
797
static void v_noreturn_ v_matchproto_(cli_func_t)
798 1
ccf_panic(struct cli *cli, const char * const *av, void *priv)
799
{
800
801 1
        (void)cli;
802 1
        (void)av;
803 1
        AZ(priv);
804 1
        AZ(strcmp("", "You asked for it"));
805
        /* NOTREACHED */
806 0
        abort();
807
}
808
809
/*--------------------------------------------------------------------*/
810
811
static struct cli_proto debug_cmds[] = {
812
        { CLICMD_DEBUG_PANIC_WORKER,            "d",    ccf_panic },
813
        { NULL }
814
};
815
816
/*--------------------------------------------------------------------*/
817
818
void
819 935
PAN_Init(void)
820
{
821
822 935
        PTOK(pthread_mutex_init(&panicstr_mtx, &mtxattr_errorcheck));
823 935
        VAS_Fail_Func = pan_ic;
824 935
        pan_vsb = &pan_vsb_storage;
825 935
        AN(heritage.panic_str);
826 935
        AN(heritage.panic_str_len);
827 935
        AN(VSB_init(pan_vsb, heritage.panic_str, heritage.panic_str_len));
828 935
        VSB_cat(pan_vsb, "This is a test\n");
829 935
        AZ(VSB_finish(pan_vsb));
830 935
        VSB_clear(pan_vsb);
831 935
        heritage.panic_str[0] = '\0';
832 935
        CLI_AddFuncs(debug_cmds);
833 935
}