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