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 240
33 240
#include <stdio.h>
34 800
#include <stdlib.h>
35 800
#include <signal.h>
36 760
37 520
#include "cache_varnishd.h"
38 400
#include "cache_transport.h"
39 280
40 280
#include "cache_filter.h"
41 280
#include "common/heritage.h"
42 240
#include "waiter/waiter.h"
43
44
#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 40
boc_state_2str(enum boc_state_e e)
72
{
73 40
        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 40
}
80
81
/*--------------------------------------------------------------------*/
82
83
static void
84 280
pan_stream_close(struct vsb *vsb, stream_close_t sc)
85
{
86
87 280
        if (sc != NULL && sc->magic == STREAM_CLOSE_MAGIC)
88 280
                VSB_printf(vsb, "%s(%s)", sc->name, sc->desc);
89
        else
90 0
                VSB_printf(vsb, "%p", sc);
91 280
}
92
93
/*--------------------------------------------------------------------*/
94
95
static void
96 280
pan_storage(struct vsb *vsb, const char *n, const struct stevedore *stv)
97
{
98
99 280
        if (stv != NULL && stv->magic == STEVEDORE_MAGIC)
100 80
                VSB_printf(vsb, "%s = %s(%s,%s),\n",
101 40
                    n, stv->name, stv->ident, stv->vclname);
102
        else
103 240
                VSB_printf(vsb, "%s = %p,\n", n, stv);
104 280
}
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 8379
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 8379
        AN(vsb);
121 8379
        va_start(ap, fmt);
122 8379
        VSB_vprintf(vsb, fmt, ap);
123 8379
        va_end(ap);
124 8379
        if (ptr == NULL) {
125 1348
                VSB_cat(vsb, " = NULL\n");
126 1348
                return (-1);
127
        }
128 7031
        VSB_printf(vsb, " = %p {", ptr);
129 7031
        if (block)
130 6951
                VSB_putc(vsb, '\n');
131 7031
        if (track) {
132 62826
                for (i = 0; i < already_idx; i++) {
133 56955
                        if (already_list[i] == ptr) {
134 1160
                                VSB_cat(vsb, "  [Already dumped, see above]");
135 1160
                                if (block)
136 1160
                                        VSB_putc(vsb, '\n');
137 1160
                                VSB_cat(vsb, "},\n");
138 1160
                                return (-2);
139
                        }
140 55795
                }
141 5871
                if (already_idx < N_ALREADY)
142 5871
                        already_list[already_idx++] = ptr;
143 5871
        }
144 5871
        uptr = ptr;
145 5871
        if (*uptr != magic) {
146 160
                VSB_printf(vsb, "  .magic = 0x%08x", *uptr);
147 160
                VSB_printf(vsb, " EXPECTED: %s=0x%08x", smagic, magic);
148 160
                if (block)
149 160
                        VSB_putc(vsb, '\n');
150 160
                VSB_cat(vsb, "}\n");
151 160
                return (-3);
152
        }
153 5711
        if (block)
154 5631
                VSB_indent(vsb, 2);
155 5711
        return (0);
156 8379
}
157
158
/*--------------------------------------------------------------------*/
159
160
static void
161 280
pan_htc(struct vsb *vsb, const struct http_conn *htc)
162
{
163
164 280
        if (PAN_dump_struct(vsb, htc, HTTP_CONN_MAGIC, "http_conn"))
165 0
                return;
166 280
        if (htc->rfd != NULL)
167 240
                VSB_printf(vsb, "fd = %d (@%p),\n", *htc->rfd, htc->rfd);
168 280
        VSB_cat(vsb, "doclose = ");
169 280
        pan_stream_close(vsb, htc->doclose);
170 280
        VSB_cat(vsb, "\n");
171 280
        WS_Panic(vsb, htc->ws);
172 560
        VSB_printf(vsb, "{rxbuf_b, rxbuf_e} = {%p, %p},\n",
173 280
            htc->rxbuf_b, htc->rxbuf_e);
174 560
        VSB_printf(vsb, "{pipeline_b, pipeline_e} = {%p, %p},\n",
175 280
            htc->pipeline_b, htc->pipeline_e);
176 560
        VSB_printf(vsb, "content_length = %jd,\n",
177 280
            (intmax_t)htc->content_length);
178 560
        VSB_printf(vsb, "body_status = %s,\n",
179 280
            htc->body_status ? htc->body_status->name : "NULL");
180 560
        VSB_printf(vsb, "first_byte_timeout = %f,\n",
181 280
            htc->first_byte_timeout);
182 560
        VSB_printf(vsb, "between_bytes_timeout = %f,\n",
183 280
            htc->between_bytes_timeout);
184 280
        VSB_indent(vsb, -2);
185 280
        VSB_cat(vsb, "},\n");
186 280
}
187
188
/*--------------------------------------------------------------------*/
189
190
static void
191 400
pan_http(struct vsb *vsb, const char *id, const struct http *h)
192
{
193
        int i;
194
195 400
        if (PAN_dump_struct(vsb, h, HTTP_MAGIC, "http[%s]", id))
196 0
                return;
197 400
        WS_Panic(vsb, h->ws);
198 400
        VSB_cat(vsb, "hdrs {\n");
199 400
        VSB_indent(vsb, 2);
200 4520
        for (i = 0; i < h->nhd; ++i) {
201 4120
                if (h->hd[i].b == NULL && h->hd[i].e == NULL)
202 800
                        continue;
203 6640
                VSB_printf(vsb, "\"%.*s\",\n",
204 3320
                    (int)(h->hd[i].e - h->hd[i].b), h->hd[i].b);
205 3320
        }
206 400
        VSB_indent(vsb, -2);
207 400
        VSB_cat(vsb, "},\n");
208 400
        VSB_indent(vsb, -2);
209 400
        VSB_cat(vsb, "},\n");
210 400
}
211
212
/*--------------------------------------------------------------------*/
213
214
static void
215 40
pan_boc(struct vsb *vsb, const struct boc *boc)
216
{
217 40
        if (PAN_dump_struct(vsb, boc, BOC_MAGIC, "boc"))
218 0
                return;
219 40
        VSB_printf(vsb, "refcnt = %u,\n", boc->refcount);
220 40
        VSB_printf(vsb, "state = %s,\n", boc_state_2str(boc->state));
221 40
        VSB_printf(vsb, "vary = %p,\n", boc->vary);
222 40
        VSB_printf(vsb, "stevedore_priv = %p,\n", boc->stevedore_priv);
223 40
        VSB_indent(vsb, -2);
224 40
        VSB_cat(vsb, "},\n");
225 40
}
226
227
/*--------------------------------------------------------------------*/
228
229
static void
230 120
pan_objcore(struct vsb *vsb, const char *typ, const struct objcore *oc)
231
{
232
        const char *p;
233
234 120
        if (PAN_dump_struct(vsb, oc, OBJCORE_MAGIC, "objcore[%s]", typ))
235 0
                return;
236 120
        VSB_printf(vsb, "refcnt = %d,\n", oc->refcnt);
237 120
        VSB_cat(vsb, "flags = {");
238
239
/*lint -save -esym(438,p) -esym(838,p) -e539 */
240 120
        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 120
        if (oc->boc != NULL)
254 40
                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 120
        if (oc->stobj->stevedore != NULL) {
260 80
                VSB_printf(vsb, " (%s", oc->stobj->stevedore->name);
261 80
                if (strlen(oc->stobj->stevedore->ident))
262 80
                        VSB_printf(vsb, " %s", oc->stobj->stevedore->ident);
263 80
                VSB_cat(vsb, ")");
264 80
                if (oc->stobj->stevedore->panic) {
265 80
                        VSB_cat(vsb, " {\n");
266 80
                        VSB_indent(vsb, 2);
267 80
                        oc->stobj->stevedore->panic(vsb, oc);
268 80
                        VSB_indent(vsb, -2);
269 80
                        VSB_cat(vsb, "}");
270 80
                }
271 80
        }
272
        VSB_cat(vsb, ",\n");
273
        VSB_indent(vsb, -2);
274
        VSB_cat(vsb, "},\n");
275
}
276
277
/*--------------------------------------------------------------------*/
278
279
static void
280 796
pan_wrk(struct vsb *vsb, const struct worker *wrk)
281
{
282
        const char *hand;
283
        unsigned m, u;
284
        const char *p;
285
286 796
        if (PAN_dump_struct(vsb, wrk, WORKER_MAGIC, "worker"))
287 516
                return;
288 280
        WS_Panic(vsb, wrk->aws);
289
290 280
        m = wrk->cur_method;
291 280
        VSB_cat(vsb, "VCL::method = ");
292 280
        if (m == 0) {
293 0
                VSB_cat(vsb, "none,\n");
294 0
                return;
295
        }
296 280
        if (!(m & 1))
297 240
                VSB_cat(vsb, "inside ");
298 280
        m &= ~1;
299 280
        hand = VCL_Method_Name(m);
300 280
        if (hand != NULL)
301 280
                VSB_printf(vsb, "%s,\n", hand);
302
        else
303 0
                VSB_printf(vsb, "0x%x,\n", m);
304
305 280
        VSB_cat(vsb, "VCL::methods = {");
306 280
        m = wrk->seen_methods;
307 280
        p = "";
308 1800
        for (u = 1; m ; u <<= 1) {
309 1520
                if (m & u) {
310 560
                        VSB_printf(vsb, "%s%s", p, VCL_Method_Name(u));
311 560
                        m &= ~u;
312 560
                        p = ", ";
313 560
                }
314 1520
        }
315 280
        VSB_cat(vsb, "},\n");
316 280
        VSB_indent(vsb, -2);
317 280
        VSB_cat(vsb, "},\n");
318 796
}
319
320
static void
321 40
pan_vfp(struct vsb *vsb, const struct vfp_ctx *vfc)
322
{
323
        struct vfp_entry *vfe;
324
325 40
        if (PAN_dump_struct(vsb, vfc, VFP_CTX_MAGIC, "vfc"))
326 0
                return;
327 40
        VSB_printf(vsb, "failed = %d,\n", vfc->failed);
328 40
        VSB_printf(vsb, "req = %p,\n", vfc->req);
329 40
        VSB_printf(vsb, "resp = %p,\n", vfc->resp);
330 40
        VSB_printf(vsb, "wrk = %p,\n", vfc->wrk);
331 40
        VSB_printf(vsb, "oc = %p,\n", vfc->oc);
332
333 40
        if (!VTAILQ_EMPTY(&vfc->vfp)) {
334 40
                VSB_cat(vsb, "filters = {\n");
335 40
                VSB_indent(vsb, 2);
336 80
                VTAILQ_FOREACH(vfe, &vfc->vfp, list) {
337 40
                        VSB_printf(vsb, "%s = %p {\n", vfe->vfp->name, vfe);
338 40
                        VSB_indent(vsb, 2);
339 40
                        VSB_printf(vsb, "priv1 = %p,\n", vfe->priv1);
340 40
                        VSB_printf(vsb, "priv2 = %zd,\n", vfe->priv2);
341 40
                        VSB_printf(vsb, "closed = %d\n", vfe->closed);
342 40
                        VSB_indent(vsb, -2);
343 40
                        VSB_cat(vsb, "},\n");
344 40
                }
345 40
                VSB_indent(vsb, -2);
346 40
                VSB_cat(vsb, "},\n");
347 40
        }
348
349 40
        VSB_printf(vsb, "obj_flags = 0x%x,\n", vfc->obj_flags);
350 40
        VSB_indent(vsb, -2);
351 40
        VSB_cat(vsb, "},\n");
352 40
}
353
354
static void
355 516
pan_busyobj(struct vsb *vsb, const struct busyobj *bo)
356
{
357
        const char *p;
358
        const struct worker *wrk;
359
360 516
        if (PAN_dump_struct(vsb, bo, BUSYOBJ_MAGIC, "busyobj"))
361 476
                return;
362 40
        VSB_printf(vsb, "end = %p,\n", bo->end);
363 40
        VSB_printf(vsb, "retries = %u,\n", bo->retries);
364
365 40
        if (bo->req != NULL)
366 0
                pan_req(vsb, bo->req);
367 40
        if (bo->sp != NULL)
368 40
                pan_sess(vsb, bo->sp);
369 40
        wrk = bo->wrk;
370 40
        if (wrk != NULL)
371 40
                pan_wrk(vsb, wrk);
372
373 40
        if (bo->vfc != NULL)
374 40
                pan_vfp(vsb, bo->vfc);
375 40
        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 40
        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 40
        WS_Panic(vsb, bo->ws);
385 40
        VSB_printf(vsb, "ws_bo = %p,\n", (void *)bo->ws_bo);
386
387
        // bereq0 left out
388 40
        if (bo->bereq != NULL && bo->bereq->ws != NULL)
389 40
                pan_http(vsb, "bereq", bo->bereq);
390 40
        if (bo->beresp != NULL && bo->beresp->ws != NULL)
391 40
                pan_http(vsb, "beresp", bo->beresp);
392 40
        if (bo->stale_oc)
393 0
                pan_objcore(vsb, "stale_oc", bo->stale_oc);
394 40
        if (bo->fetch_objcore)
395 40
                pan_objcore(vsb, "fetch", bo->fetch_objcore);
396
397 40
        if (VALID_OBJ(bo->htc, HTTP_CONN_MAGIC))
398 40
                pan_htc(vsb, bo->htc);
399
400
        // fetch_task left out
401
402 40
        VSB_cat(vsb, "flags = {");
403 40
        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 40
        if (bo->director_resp == bo->director_req)
418 40
                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 40
        if (wrk != NULL)
423 40
                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 240
pan_top(struct vsb *vsb, const struct reqtop *top)
433
{
434 240
        if (PAN_dump_struct(vsb, top, REQTOP_MAGIC, "top"))
435 0
                return;
436 240
        pan_req(vsb, top->topreq);
437 240
        pan_privs(vsb, top->privs);
438 240
        VCL_Panic(vsb, "vcl0", top->vcl0);
439 240
        VSB_indent(vsb, -2);
440 240
        VSB_cat(vsb, "},\n");
441 240
}
442
443
/*--------------------------------------------------------------------*/
444
445
static void
446 756
pan_req(struct vsb *vsb, const struct req *req)
447
{
448
        const struct transport *xp;
449
        const struct worker *wrk;
450
451 756
        if (PAN_dump_struct(vsb, req, REQ_MAGIC, "req"))
452 516
                return;
453 240
        xp = req->transport;
454 480
        VSB_printf(vsb, "vxid = %ju, transport = %s", VXID(req->vsl->wid),
455 240
            xp == NULL ? "NULL" : xp->name);
456
457 240
        if (xp != NULL && xp->req_panic != NULL) {
458 200
                VSB_cat(vsb, " {\n");
459 200
                VSB_indent(vsb, 2);
460 200
                xp->req_panic(vsb, req);
461 200
                VSB_indent(vsb, -2);
462 200
                VSB_cat(vsb, "}");
463 200
        }
464 240
        VSB_cat(vsb, "\n");
465 240
        if (req->req_step == NULL)
466 0
                VSB_cat(vsb, "step = R_STP_TRANSPORT\n");
467
        else
468 240
                VSB_printf(vsb, "step = %s\n", req->req_step->name);
469
470 240
        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 240
        if (req->vdp_filter_list != NULL) {
475 80
                VSB_printf(vsb, "vdp_filter_list = \"%s\",\n",
476 40
                    req->vdp_filter_list);
477 40
        }
478
479 480
        VSB_printf(vsb, "req_body = %s,\n",
480 240
            req->req_body_status ? req->req_body_status->name : "NULL");
481
482 240
        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 480
        VSB_printf(vsb, "restarts = %u, esi_level = %u,\n",
488 240
            req->restarts, req->esi_level);
489
490 480
        VSB_printf(vsb, "vary_b = %p, vary_e = %p,\n",
491 240
            req->vary_b, req->vary_e);
492
493 480
        VSB_printf(vsb, "d_ttl = %f, d_grace = %f,\n",
494 240
            req->d_ttl, req->d_grace);
495
496 240
        pan_storage(vsb, "storage", req->storage);
497
498 240
        VDI_Panic(req->director_hint, vsb, "director_hint");
499
500 240
        if (req->sp != NULL)
501 240
                pan_sess(vsb, req->sp);
502
503 240
        wrk = req->wrk;
504 240
        if (wrk != NULL)
505 240
                pan_wrk(vsb, wrk);
506
507 240
        WS_Panic(vsb, req->ws);
508 240
        if (VALID_OBJ(req->htc, HTTP_CONN_MAGIC))
509 240
                pan_htc(vsb, req->htc);
510 240
        pan_http(vsb, "req", req->http);
511 240
        if (req->resp != NULL && req->resp->ws != NULL)
512 80
                pan_http(vsb, "resp", req->resp);
513 240
        if (req->vdc != NULL)
514 240
                VDP_Panic(vsb, req->vdc);
515
516 240
        VCL_Panic(vsb, "vcl", req->vcl);
517 240
        if (wrk != NULL)
518 240
                VPI_Panic(vsb, wrk->vpi, req->vcl);
519
520 240
        if (req->body_oc != NULL)
521 0
                pan_objcore(vsb, "BODY", req->body_oc);
522 240
        if (req->objcore != NULL)
523 80
                pan_objcore(vsb, "REQ", req->objcore);
524
525 240
        VSB_cat(vsb, "flags = {\n");
526 240
        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 240
        if (req->top != NULL)
535 240
                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 280
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 280
        if (PAN_dump_struct(vsb, sp, SESS_MAGIC, "sess"))
563 0
                return;
564 560
        VSB_printf(vsb, "fd = %d, vxid = %ju,\n",
565 280
            sp->fd, VXID(sp->vxid));
566 280
        VSB_printf(vsb, "t_open = %f,\n", sp->t_open);
567 280
        VSB_printf(vsb, "t_idle = %f,\n", sp->t_idle);
568
569 280
        if (! VALID_OBJ(sp, SESS_MAGIC)) {
570 0
                VSB_indent(vsb, -2);
571 0
                VSB_cat(vsb, "},\n");
572 0
                return;
573
        }
574
575 280
        WS_Panic(vsb, sp->ws);
576 280
        xp = XPORT_ByNumber(sp->sattr[SA_TRANSPORT]);
577 560
        VSB_printf(vsb, "transport = %s",
578 280
            xp == NULL ? "<none>" : xp->name);
579 280
        if (xp != NULL && xp->sess_panic != NULL) {
580 280
                VSB_cat(vsb, " {\n");
581 280
                VSB_indent(vsb, 2);
582 280
                xp->sess_panic(vsb, sp);
583 280
                VSB_indent(vsb, -2);
584 280
                VSB_cat(vsb, "}");
585 280
        }
586 280
        VSB_cat(vsb, "\n");
587
588
        // duplicated below, remove ?
589 280
        ci = SES_Get_String_Attr(sp, SA_CLIENT_IP);
590 280
        cp = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
591 280
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC))
592 560
                VSB_printf(vsb, "client = %s %s %s,\n", ci, cp,
593 280
                           sp->listen_sock->endpoint);
594
        else
595 0
                VSB_printf(vsb, "client = %s %s <unknown>\n", ci, cp);
596
597 280
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC)) {
598 560
                VSB_printf(vsb, "local.endpoint = %s,\n",
599 280
                           sp->listen_sock->endpoint);
600 560
                VSB_printf(vsb, "local.socket = %s,\n",
601 280
                           sp->listen_sock->name);
602 280
        }
603 280
        pan_addr(vsb, sp, local);
604 280
        pan_addr(vsb, sp, remote);
605 280
        pan_addr(vsb, sp, server);
606 280
        pan_addr(vsb, sp, client);
607
608 280
        VSB_indent(vsb, -2);
609 280
        VSB_cat(vsb, "},\n");
610 280
}
611
612
/*--------------------------------------------------------------------*/
613
614
static void
615 516
pan_backtrace(struct vsb *vsb)
616
{
617
618 516
        VSB_cat(vsb, "Backtrace:\n");
619 516
        VSB_indent(vsb, 2);
620 516
        VBT_format(vsb);
621 516
        VSB_indent(vsb, -2);
622 516
}
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 516
pan_argv(struct vsb *vsb)
653
{
654
        int i;
655
656 516
        VSB_cat(pan_vsb, "argv = {\n");
657 516
        VSB_indent(vsb, 2);
658 15586
        for (i = 0; i < heritage.argc; i++) {
659 15070
                VSB_printf(vsb, "[%d] = ", i);
660 15070
                VSB_quote(vsb, heritage.argv[i], -1, VSB_QUOTE_CSTR);
661 15070
                VSB_cat(vsb, ",\n");
662 15070
        }
663 516
        VSB_indent(vsb, -2);
664 516
        VSB_cat(vsb, "}\n");
665
666 516
}
667
/*--------------------------------------------------------------------*/
668
669
static void __attribute__((__noreturn__))
670 516
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 516
        int i, err = errno;
679
680 516
        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 516
        do {
687 516
                i = pthread_mutex_trylock(&panicstr_mtx);
688 516
                if (i != 0)
689 0
                        sleep (1);
690 516
        } while (i != 0);
691
692 516
        assert (VSB_len(pan_vsb) == 0);
693
694 516
        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 516
        memset(&sa, 0, sizeof sa);
702 516
        sa.sa_handler = SIG_DFL;
703 516
        (void)sigaction(SIGSEGV, &sa, NULL);
704
        /* Set SIGABRT back to default so the final abort() has the
705
           desired effect */
706 516
        (void)sigaction(SIGABRT, &sa, NULL);
707
708 516
        switch (kind) {
709
        case VAS_WRONG:
710 492
                VSB_printf(pan_vsb,
711 246
                    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
712 246
                break;
713
        case VAS_VCL:
714 240
                VSB_printf(pan_vsb,
715 120
                    "Panic from VCL:\n  %s\n", cond);
716 120
                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 150
        case VAS_ASSERT:
729
        default:
730 300
                VSB_printf(pan_vsb,
731
                    "Assert error in %s(), %s line %d:\n"
732
                    "  Condition(%s) not true.\n",
733 150
                    func, file, line, cond);
734 150
                break;
735
        }
736 1032
        VSB_printf(pan_vsb, "version = %s, vrt api = %u.%u\n",
737 516
            VCS_String("V"), VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
738 1032
        VSB_printf(pan_vsb, "ident = %s,%s\n",
739 516
            heritage.ident, Waiter_GetName());
740 1032
        VSB_printf(pan_vsb, "now = %f (mono), %f (real)\n",
741 516
            VTIM_mono(), VTIM_real());
742
743 516
        pan_backtrace(pan_vsb);
744
745 516
        if (err)
746 70
                VSB_printf(pan_vsb, "errno = %d (%s)\n", err, VAS_errtxt(err));
747
748 516
        pan_argv(pan_vsb);
749
750 516
        VSB_printf(pan_vsb, "pthread.self = %p\n", TRUST_ME(pthread_self()));
751
752 516
        q = THR_GetName();
753 516
        if (q != NULL)
754 516
                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 516
        if (!FEATURE(FEATURE_SHORT_PANIC)) {
761 516
                req = THR_GetRequest();
762 516
                VSB_cat(pan_vsb, "thr.");
763 516
                pan_req(pan_vsb, req);
764 516
                if (req != NULL)
765 240
                        VSL_Flush(req->vsl, 0);
766 516
                bo = THR_GetBusyobj();
767 516
                VSB_cat(pan_vsb, "thr.");
768 516
                pan_busyobj(pan_vsb, bo);
769 516
                if (bo != NULL)
770 40
                        VSL_Flush(bo->vsl, 0);
771 516
                wrk = THR_GetWorker();
772 516
                VSB_cat(pan_vsb, "thr.");
773 516
                pan_wrk(pan_vsb, wrk);
774 516
                VMOD_Panic(pan_vsb);
775 516
                pan_pool(pan_vsb);
776 516
        } else {
777 0
                VSB_cat(pan_vsb, "Feature short panic suppressed details.\n");
778
        }
779 516
        VSB_cat(pan_vsb, "\n");
780 516
        VSB_putc(pan_vsb, '\0');        /* NUL termination */
781
782 516
        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 516
        if (pthread_getspecific(panic_key))     /* ie: always */
790 516
                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 40
ccf_panic(struct cli *cli, const char * const *av, void *priv)
799
{
800
801 40
        (void)cli;
802 40
        (void)av;
803 40
        AZ(priv);
804 40
        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 36676
PAN_Init(void)
820
{
821
822 36676
        PTOK(pthread_mutex_init(&panicstr_mtx, &mtxattr_errorcheck));
823 36676
        VAS_Fail_Func = pan_ic;
824 36676
        pan_vsb = &pan_vsb_storage;
825 36676
        AN(heritage.panic_str);
826 36676
        AN(heritage.panic_str_len);
827 36676
        AN(VSB_init(pan_vsb, heritage.panic_str, heritage.panic_str_len));
828 36676
        VSB_cat(pan_vsb, "This is a test\n");
829 36676
        AZ(VSB_finish(pan_vsb));
830 36676
        VSB_clear(pan_vsb);
831 36676
        heritage.panic_str[0] = '\0';
832 36676
        CLI_AddFuncs(debug_cmds);
833 36676
}