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