varnish-cache/bin/varnishd/cache/cache_panic.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Dag-Erling Smørgrav <des@des.no>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <execinfo.h>
33
#include <errno.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <signal.h>
37
38
#include "vtim.h"
39
#include "vcs.h"
40
41
#include "cache_varnishd.h"
42
#include "cache_transport.h"
43
44
#include "cache_filter.h"
45
#include "common/heritage.h"
46
#include "waiter/waiter.h"
47
48
#include "storage/storage.h"
49
#include "vcli_serve.h"
50
51
/*
52
 * The panic string is constructed in memory, then copied to the
53
 * shared memory.
54
 *
55
 * It can be extracted post-mortem from a core dump using gdb:
56
 *
57
 * (gdb) printf "%s", panicstr
58
 */
59
60
static struct vsb pan_vsb_storage, *pan_vsb;
61
static pthread_mutex_t panicstr_mtx;
62
63
static void pan_sess(struct vsb *, const struct sess *);
64
65
/*--------------------------------------------------------------------*/
66
67
const char *
68 4461
body_status_2str(enum body_status e)
69
{
70 4461
        switch (e) {
71
#define BODYSTATUS(U,l) case BS_##U: return (#l);
72
#include "tbl/body_status.h"
73
        default:
74 0
                return ("?");
75
        }
76
}
77
78
/*--------------------------------------------------------------------*/
79
80
static const char *
81 12
reqbody_status_2str(enum req_body_state_e e)
82
{
83 12
        switch (e) {
84
#define REQ_BODY(U) case REQ_BODY_##U: return("R_BODY_" #U);
85
#include "tbl/req_body.h"
86
        default:
87 0
                return("?");
88
        }
89
}
90
91
/*--------------------------------------------------------------------*/
92
93
static const char *
94 3
boc_state_2str(enum boc_state_e e)
95
{
96 3
        switch (e) {
97
#define BOC_STATE(U,l) case BOS_##U: return(#l);
98
#include "tbl/boc_state.h"
99
        default:
100 0
                return ("?");
101
        }
102
}
103
104
/*--------------------------------------------------------------------*/
105
106
const char *
107 4389
sess_close_2str(enum sess_close sc, int want_desc)
108
{
109 4389
        switch (sc) {
110 15
        case SC_NULL:           return(want_desc ? "(null)": "NULL");
111
#define SESS_CLOSE(nm, s, err, desc)                    \
112
        case SC_##nm: return(want_desc ? desc : #nm);
113
#include "tbl/sess_close.h"
114
115 0
        default:                return(want_desc ? "(invalid)" : "INVALID");
116
        }
117
}
118
119
/*--------------------------------------------------------------------*/
120
121
#define N_ALREADY 256
122
static const void *already_list[N_ALREADY];
123
static int already_idx;
124
125
int
126 192
PAN_already(struct vsb *vsb, const void *ptr)
127
{
128
        int i;
129
130 192
        if (ptr == NULL) {
131 24
                VSB_printf(vsb, "},\n");
132 24
                return (1);
133
        }
134 849
        for (i = 0; i < already_idx; i++) {
135 714
                if (already_list[i] == ptr) {
136 33
                        VSB_printf(vsb, "  [Already dumped, see above]\n");
137 33
                        VSB_printf(vsb, "},\n");
138 33
                        return (1);
139
                }
140
        }
141 135
        if (already_idx < N_ALREADY)
142 135
                already_list[already_idx++] = ptr;
143 135
        return (0);
144
}
145
146
/*--------------------------------------------------------------------*/
147
148
static void
149 75
pan_ws(struct vsb *vsb, const struct ws *ws)
150
{
151
152 75
        VSB_printf(vsb, "ws = %p {\n", ws);
153 75
        if (PAN_already(vsb, ws))
154 36
                return;
155 39
        VSB_indent(vsb, 2);
156 39
        PAN_CheckMagic(vsb, ws, WS_MAGIC);
157 39
        if (ws->id[0] != '\0' && (!(ws->id[0] & 0x20)))
158 0
                VSB_printf(vsb, "OVERFLOWED ");
159 39
        VSB_printf(vsb, "id = \"%s\",\n", ws->id);
160 39
        VSB_printf(vsb, "{s, f, r, e} = {%p", ws->s);
161 39
        if (ws->f >= ws->s)
162 39
                VSB_printf(vsb, ", +%ld", (long) (ws->f - ws->s));
163
        else
164 0
                VSB_printf(vsb, ", %p", ws->f);
165 39
        if (ws->r >= ws->s)
166 0
                VSB_printf(vsb, ", +%ld", (long) (ws->r - ws->s));
167
        else
168 39
                VSB_printf(vsb, ", %p", ws->r);
169 39
        if (ws->e >= ws->s)
170 39
                VSB_printf(vsb, ", +%ld", (long) (ws->e - ws->s));
171
        else
172 0
                VSB_printf(vsb, ", %p", ws->e);
173 39
        VSB_printf(vsb, "},\n");
174 39
        VSB_indent(vsb, -2);
175 39
        VSB_printf(vsb, "},\n");
176
}
177
178
/*--------------------------------------------------------------------*/
179
180
static void
181 15
pan_htc(struct vsb *vsb, const struct http_conn *htc)
182
{
183
184 15
        VSB_printf(vsb, "http_conn = %p {\n", htc);
185 15
        if (PAN_already(vsb, htc))
186 0
                return;
187 15
        VSB_indent(vsb, 2);
188 15
        PAN_CheckMagic(vsb, htc, HTTP_CONN_MAGIC);
189 15
        if (htc->rfd != NULL)
190 12
                VSB_printf(vsb, "fd = %d (@%p),\n", *htc->rfd, htc->rfd);
191 15
        VSB_printf(vsb, "doclose = %s,\n", sess_close_2str(htc->doclose, 0));
192 15
        pan_ws(vsb, htc->ws);
193 15
        VSB_printf(vsb, "{rxbuf_b, rxbuf_e} = {%p, %p},\n",
194
            htc->rxbuf_b, htc->rxbuf_e);
195 15
        VSB_printf(vsb, "{pipeline_b, pipeline_e} = {%p, %p},\n",
196
            htc->pipeline_b, htc->pipeline_e);
197 15
        VSB_printf(vsb, "content_length = %jd,\n",
198 15
            (intmax_t)htc->content_length);
199 15
        VSB_printf(vsb, "body_status = %s,\n",
200
            body_status_2str(htc->body_status));
201 15
        VSB_printf(vsb, "first_byte_timeout = %f,\n",
202
            htc->first_byte_timeout);
203 15
        VSB_printf(vsb, "between_bytes_timeout = %f,\n",
204
            htc->between_bytes_timeout);
205 15
        VSB_indent(vsb, -2);
206 15
        VSB_printf(vsb, "},\n");
207
}
208
209
/*--------------------------------------------------------------------*/
210
211
static void
212 21
pan_http(struct vsb *vsb, const char *id, const struct http *h)
213
{
214
        int i;
215
216 21
        VSB_printf(vsb, "http[%s] = %p {\n", id, h);
217 21
        if (PAN_already(vsb, h))
218 0
                return;
219 21
        VSB_indent(vsb, 2);
220 21
        PAN_CheckMagic(vsb, h, HTTP_MAGIC);
221 21
        pan_ws(vsb, h->ws);
222 21
        VSB_printf(vsb, "hdrs {\n");
223 21
        VSB_indent(vsb, 2);
224 192
        for (i = 0; i < h->nhd; ++i) {
225 171
                if (h->hd[i].b == NULL && h->hd[i].e == NULL)
226 42
                        continue;
227 258
                VSB_printf(vsb, "\"%.*s\",\n",
228 258
                    (int)(h->hd[i].e - h->hd[i].b), h->hd[i].b);
229
        }
230 21
        VSB_indent(vsb, -2);
231 21
        VSB_printf(vsb, "},\n");
232 21
        VSB_indent(vsb, -2);
233 21
        VSB_printf(vsb, "},\n");
234
}
235
236
/*--------------------------------------------------------------------*/
237
static void
238 3
pan_boc(struct vsb *vsb, const struct boc *boc)
239
{
240 3
        VSB_printf(vsb, "boc = %p {\n", boc);
241 3
        if (PAN_already(vsb, boc))
242 0
                return;
243 3
        VSB_indent(vsb, 2);
244 3
        PAN_CheckMagic(vsb, boc, BOC_MAGIC);
245 3
        VSB_printf(vsb, "refcnt = %u,\n", boc->refcount);
246 3
        VSB_printf(vsb, "state = %s,\n", boc_state_2str(boc->state));
247 3
        VSB_printf(vsb, "vary = %p,\n", boc->vary);
248 3
        VSB_printf(vsb, "stevedore_priv = %p,\n", boc->stevedore_priv);
249 3
        VSB_indent(vsb, -2);
250 3
        VSB_printf(vsb, "},\n");
251
}
252
253
/*--------------------------------------------------------------------*/
254
255
static void
256 6
pan_objcore(struct vsb *vsb, const char *typ, const struct objcore *oc)
257
{
258
        const char *p;
259
260 6
        VSB_printf(vsb, "objcore[%s] = %p {\n", typ, oc);
261 6
        if (PAN_already(vsb, oc))
262 0
                return;
263 6
        VSB_indent(vsb, 2);
264 6
        PAN_CheckMagic(vsb, oc, OBJCORE_MAGIC);
265 6
        VSB_printf(vsb, "refcnt = %d,\n", oc->refcnt);
266 6
        VSB_printf(vsb, "flags = {");
267
268
/*lint -save -esym(438,p) -esym(838,p) -e539 */
269 6
        p = "";
270
#define OC_FLAG(U, l, v) \
271
        if (oc->flags & v) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
272
#include "tbl/oc_flags.h"
273 6
        VSB_printf(vsb, "},\n");
274 6
        VSB_printf(vsb, "exp_flags = {");
275 6
        p = "";
276
#define OC_EXP_FLAG(U, l, v) \
277
        if (oc->exp_flags & v) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
278
#include "tbl/oc_exp_flags.h"
279
/*lint -restore */
280 6
        VSB_printf(vsb, "},\n");
281
282 6
        if (oc->boc != NULL)
283 3
                pan_boc(vsb, oc->boc);
284 18
        VSB_printf(vsb, "exp = {%f, %f, %f, %f},\n",
285 18
            oc->t_origin, oc->ttl, oc->grace, oc->keep);
286 6
        VSB_printf(vsb, "objhead = %p,\n", oc->objhead);
287 6
        VSB_printf(vsb, "stevedore = %p", oc->stobj->stevedore);
288 6
        if (oc->stobj->stevedore != NULL) {
289 3
                VSB_printf(vsb, " (%s", oc->stobj->stevedore->name);
290 3
                if (strlen(oc->stobj->stevedore->ident))
291 3
                        VSB_printf(vsb, " %s", oc->stobj->stevedore->ident);
292 3
                VSB_printf(vsb, ")");
293 3
                if (oc->stobj->stevedore->panic) {
294 3
                        VSB_printf(vsb, " {\n");
295 3
                        VSB_indent(vsb, 2);
296 3
                        oc->stobj->stevedore->panic(vsb, oc);
297 3
                        VSB_indent(vsb, -2);
298 3
                        VSB_printf(vsb, "}");
299
                }
300
        }
301 6
        VSB_printf(vsb, ",\n");
302 6
        VSB_indent(vsb, -2);
303 6
        VSB_printf(vsb, "},\n");
304
}
305
306
/*--------------------------------------------------------------------*/
307
308
static void
309 12
pan_wrk(struct vsb *vsb, const struct worker *wrk)
310
{
311
        const char *hand;
312
        unsigned m, u;
313
        const char *p;
314
315 12
        VSB_printf(vsb, "worker = %p {\n", wrk);
316 12
        if (PAN_already(vsb, wrk))
317 0
                return;
318 12
        VSB_indent(vsb, 2);
319 12
        PAN_CheckMagic(vsb, wrk, WORKER_MAGIC);
320 12
        pan_ws(vsb, wrk->aws);
321
322 12
        m = wrk->cur_method;
323 12
        VSB_printf(vsb, "VCL::method = ");
324 12
        if (m == 0) {
325 0
                VSB_printf(vsb, "none,\n");
326 0
                return;
327
        }
328 12
        if (!(m & 1))
329 12
                VSB_printf(vsb, "inside ");
330 12
        m &= ~1;
331 12
        hand = VCL_Method_Name(m);
332 12
        if (hand != NULL)
333 12
                VSB_printf(vsb, "%s,\n", hand);
334
        else
335 0
                VSB_printf(vsb, "0x%x,\n", m);
336
337 12
        hand = VCL_Return_Name(wrk->handling);
338 12
        if (hand != NULL)
339 0
                VSB_printf(vsb, "VCL::return = %s,\n", hand);
340
        else
341 12
                VSB_printf(vsb, "VCL::return = 0x%x,\n", wrk->handling);
342 12
        VSB_printf(vsb, "VCL::methods = {");
343 12
        m = wrk->seen_methods;
344 12
        p = "";
345 57
        for (u = 1; m ; u <<= 1) {
346 45
                if (m & u) {
347 21
                        VSB_printf(vsb, "%s%s", p, VCL_Method_Name(u));
348 21
                        m &= ~u;
349 21
                        p = ", ";
350
                }
351
        }
352 12
        VSB_printf(vsb, "},\n");
353 12
        VSB_indent(vsb, -2);
354 12
        VSB_printf(vsb, "},\n");
355
}
356
357
static void
358 3
pan_vfp(struct vsb *vsb, const struct vfp_ctx *vfc)
359
{
360
        struct vfp_entry *vfe;
361
362 3
        VSB_printf(vsb, "vfc = %p {\n", vfc);
363 3
        VSB_indent(vsb, 2);
364 3
        VSB_printf(vsb, "failed = %d,\n", vfc->failed);
365 3
        VSB_printf(vsb, "req = %p,\n", vfc->req);
366 3
        VSB_printf(vsb, "resp = %p,\n", vfc->resp);
367 3
        VSB_printf(vsb, "wrk = %p,\n", vfc->wrk);
368 3
        VSB_printf(vsb, "oc = %p,\n", vfc->oc);
369
370 3
        if (!VTAILQ_EMPTY(&vfc->vfp)) {
371 3
                VSB_printf(vsb, "filters = {\n");
372 3
                VSB_indent(vsb, 2);
373 6
                VTAILQ_FOREACH(vfe, &vfc->vfp, list) {
374 3
                        VSB_printf(vsb, "%s = %p {\n",
375 3
                                   vfe->vfp->name, vfe);
376 3
                        VSB_indent(vsb, 2);
377 3
                        VSB_printf(vsb, "priv1 = %p,\n", vfe->priv1);
378 3
                        VSB_printf(vsb, "priv2 = %zd,\n", vfe->priv2);
379 3
                        VSB_printf(vsb, "closed = %d\n", vfe->closed);
380 3
                        VSB_indent(vsb, -2);
381 3
                        VSB_printf(vsb, "},\n");
382
                }
383 3
                VSB_indent(vsb, -2);
384 3
                VSB_printf(vsb, "},\n");
385
        }
386
387 3
        VSB_printf(vsb, "obj_flags = 0x%x,\n", vfc->obj_flags);
388 3
        VSB_indent(vsb, -2);
389 3
        VSB_printf(vsb, "},\n");
390 3
}
391
392
393
static void
394 18
pan_busyobj(struct vsb *vsb, const struct busyobj *bo)
395
{
396
        const char *p;
397
398 18
        VSB_printf(vsb, "busyobj = %p {\n", bo);
399 18
        if (PAN_already(vsb, bo))
400 15
                return;
401 3
        VSB_indent(vsb, 2);
402 3
        PAN_CheckMagic(vsb, bo, BUSYOBJ_MAGIC);
403 3
        pan_ws(vsb, bo->ws);
404 3
        VSB_printf(vsb, "retries = %d, ", bo->retries);
405 3
        VSB_printf(vsb, "flags = {");
406 3
        p = "";
407
/*lint -save -esym(438,p) -e539 */
408
#define BO_FLAG(l, r, w, d) \
409
        if (bo->l) { VSB_printf(vsb, "%s" #l, p); p = ", "; }
410
#include "tbl/bo_flags.h"
411
/*lint -restore */
412 3
        VSB_printf(vsb, "},\n");
413
414 3
        if (VALID_OBJ(bo->htc, HTTP_CONN_MAGIC))
415 3
                pan_htc(vsb, bo->htc);
416
417 3
        if (bo->vfc)
418 3
                pan_vfp(vsb, bo->vfc);
419
420 3
        VDI_Panic(bo->director_req, vsb, "director_req");
421 3
        if (bo->director_resp == bo->director_req)
422 3
                VSB_printf(vsb, "director_resp = director_req,\n");
423
        else
424 0
                VDI_Panic(bo->director_resp, vsb, "director_resp");
425 3
        if (bo->bereq != NULL && bo->bereq->ws != NULL)
426 3
                pan_http(vsb, "bereq", bo->bereq);
427 3
        if (bo->beresp != NULL && bo->beresp->ws != NULL)
428 3
                pan_http(vsb, "beresp", bo->beresp);
429 3
        if (bo->fetch_objcore)
430 3
                pan_objcore(vsb, "fetch", bo->fetch_objcore);
431 3
        if (bo->stale_oc)
432 0
                pan_objcore(vsb, "ims", bo->stale_oc);
433 3
        VCL_Panic(vsb, bo->vcl);
434 3
        VMOD_Panic(vsb);
435 3
        VSB_indent(vsb, -2);
436 3
        VSB_printf(vsb, "},\n");
437
}
438
439
/*--------------------------------------------------------------------*/
440
441
static void
442 18
pan_req(struct vsb *vsb, const struct req *req)
443
{
444
        const char *stp;
445
        const struct transport *xp;
446
447 18
        VSB_printf(vsb, "req = %p {\n", req);
448 18
        if (PAN_already(vsb, req))
449 6
                return;
450 12
        VSB_indent(vsb, 2);
451 12
        PAN_CheckMagic(vsb, req, REQ_MAGIC);
452 12
        xp = req->transport;
453 12
        VSB_printf(vsb, "vxid = %u, transport = %s", VXID(req->vsl->wid),
454
            xp == NULL ? "NULL" : xp->name);
455
456 12
        if (xp != NULL && xp->req_panic != NULL) {
457 9
                VSB_printf(vsb, " {\n");
458 9
                VSB_indent(vsb, 2);
459 9
                xp->req_panic(vsb, req);
460 9
                VSB_indent(vsb, -2);
461 9
                VSB_printf(vsb, "}");
462
        }
463 12
        VSB_printf(vsb, "\n");
464 12
        switch (req->req_step) {
465
#define REQ_STEP(l, u, arg) case R_STP_##u: stp = "R_STP_" #u; break;
466
#include "tbl/steps.h"
467 0
                default: stp = NULL;
468
        }
469 12
        if (stp != NULL)
470 12
                VSB_printf(vsb, "step = %s,\n", stp);
471
        else
472 0
                VSB_printf(vsb, "step = 0x%x,\n", req->req_step);
473
474 12
        VSB_printf(vsb, "req_body = %s,\n",
475
            reqbody_status_2str(req->req_body_status));
476
477 12
        if (req->err_code)
478 0
                VSB_printf(vsb,
479 0
                    "err_code = %d, err_reason = %s,\n", req->err_code,
480 0
                    req->err_reason ? req->err_reason : "(null)");
481
482 12
        VSB_printf(vsb, "restarts = %d, esi_level = %d,\n",
483
            req->restarts, req->esi_level);
484
485 12
        if (req->sp != NULL)
486 12
                pan_sess(vsb, req->sp);
487
488 12
        if (req->wrk != NULL)
489 12
                pan_wrk(vsb, req->wrk);
490
491 12
        pan_ws(vsb, req->ws);
492 12
        if (VALID_OBJ(req->htc, HTTP_CONN_MAGIC))
493 12
                pan_htc(vsb, req->htc);
494 12
        pan_http(vsb, "req", req->http);
495 12
        if (req->resp->ws != NULL)
496 3
                pan_http(vsb, "resp", req->resp);
497
498 12
        VCL_Panic(vsb, req->vcl);
499 12
        VMOD_Panic(vsb);
500
501 12
        if (req->body_oc != NULL)
502 0
                pan_objcore(vsb, "BODY", req->body_oc);
503 12
        if (req->objcore != NULL)
504 3
                pan_objcore(vsb, "REQ", req->objcore);
505
506 12
        VSB_printf(vsb, "flags = {\n");
507 12
        VSB_indent(vsb, 2);
508
#define REQ_FLAG(l, r, w, d) if (req->l) VSB_printf(vsb, #l ",\n");
509
#include "tbl/req_flags.h"
510 12
        VSB_indent(vsb, -2);
511 12
        VSB_printf(vsb, "},\n");
512
513 12
        pan_privs(vsb, req->privs);
514
515 12
        VSB_indent(vsb, -2);
516 12
        VSB_printf(vsb, "},\n");
517
}
518
519
/*--------------------------------------------------------------------*/
520
521
static void
522 12
pan_sess(struct vsb *vsb, const struct sess *sp)
523
{
524
        const char *ci;
525
        const char *cp;
526
        const struct transport *xp;
527
528 12
        VSB_printf(vsb, "sp = %p {\n", sp);
529 12
        if (PAN_already(vsb, sp))
530 0
                return;
531 12
        VSB_indent(vsb, 2);
532 12
        PAN_CheckMagic(vsb, sp, SESS_MAGIC);
533 12
        xp = XPORT_ByNumber(sp->sattr[SA_TRANSPORT]);
534 12
        VSB_printf(vsb, "fd = %d, vxid = %u,\n",
535 12
            sp->fd, VXID(sp->vxid));
536 12
        VSB_printf(vsb, "t_open = %f,\n", sp->t_open);
537 12
        VSB_printf(vsb, "t_idle = %f,\n", sp->t_idle);
538 12
        pan_ws(vsb, sp->ws);
539 12
        VSB_printf(vsb, "transport = %s",
540
            xp == NULL ? "<none>" : xp->name);
541 12
        if (xp != NULL && xp->sess_panic != NULL) {
542 12
                VSB_printf(vsb, " {\n");
543 12
                VSB_indent(vsb, 2);
544 12
                xp->sess_panic(vsb, sp);
545 12
                VSB_indent(vsb, -2);
546 12
                VSB_printf(vsb, "}");
547
        }
548 12
        VSB_printf(vsb, "\n");
549 12
        ci = SES_Get_String_Attr(sp, SA_CLIENT_IP);
550 12
        cp = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
551 12
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC))
552 12
                VSB_printf(vsb, "client = %s %s %s,\n", ci, cp,
553 12
                           sp->listen_sock->endpoint);
554
        else
555 0
                VSB_printf(vsb, "client = %s %s <unknown>\n", ci, cp);
556
557 12
        VSB_indent(vsb, -2);
558 12
        VSB_printf(vsb, "},\n");
559
}
560
561
/*--------------------------------------------------------------------*/
562
563
#define BACKTRACE_LEVELS        10
564
565
static void
566 18
pan_backtrace(struct vsb *vsb)
567
{
568
        void *array[BACKTRACE_LEVELS];
569
        size_t size;
570
        size_t i;
571
        char **strings;
572
        char *p;
573
        char buf[32];
574
575 18
        size = backtrace (array, BACKTRACE_LEVELS);
576 18
        if (size > BACKTRACE_LEVELS) {
577 0
                VSB_printf(vsb, "Backtrace not available (ret=%zu)\n", size);
578 0
                return;
579
        }
580 18
        VSB_printf(vsb, "Backtrace:\n");
581 18
        VSB_indent(vsb, 2);
582 162
        for (i = 0; i < size; i++) {
583 144
                bprintf(buf, "%p", array[i]);
584 144
                VSB_printf(vsb, "%s: ", buf);
585 144
                strings = backtrace_symbols(&array[i], 1);
586 144
                if (strings == NULL || strings[0] == NULL) {
587 0
                        VSB_printf(vsb, "(?)");
588
                } else {
589 144
                        p = strings[0];
590 144
                        if (!memcmp(buf, p, strlen(buf))) {
591 144
                                p += strlen(buf);
592 144
                                if (*p == ':')
593 0
                                        p++;
594 432
                                while (*p == ' ')
595 144
                                        p++;
596
                        }
597 144
                        VSB_printf(vsb, "%s", p);
598
                }
599 144
                VSB_printf (vsb, "\n");
600
        }
601 18
        VSB_indent(vsb, -2);
602
}
603
604
/*--------------------------------------------------------------------*/
605
606
static void __attribute__((__noreturn__))
607 18
pan_ic(const char *func, const char *file, int line, const char *cond,
608
    enum vas_e kind)
609
{
610
        const char *q;
611
        struct req *req;
612
        struct busyobj *bo;
613
        struct sigaction sa;
614 18
        int err = errno;
615
616 18
        AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released,
617
                                                  we're going to die
618
                                                  anyway */
619
620
        /*
621
         * should we trigger a SIGSEGV while handling a panic, our sigsegv
622
         * handler would hide the panic, so we need to reset the handler to
623
         * default
624
         */
625 18
        memset(&sa, 0, sizeof sa);
626 18
        sa.sa_handler = SIG_DFL;
627 18
        (void)sigaction(SIGSEGV, &sa, NULL);
628
        /* Set SIGABRT back to default so the final abort() has the
629
           desired effect */
630 18
        (void)sigaction(SIGABRT, &sa, NULL);
631
632 18
        switch (kind) {
633
        case VAS_WRONG:
634 6
                VSB_printf(pan_vsb,
635
                    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
636 6
                break;
637
        case VAS_VCL:
638 9
                VSB_printf(pan_vsb,
639
                    "Panic from VCL:\n  %s\n", cond);
640 9
                break;
641
        case VAS_MISSING:
642 0
                VSB_printf(pan_vsb,
643
                    "Missing errorhandling code in %s(), %s line %d:\n"
644
                    "  Condition(%s) not true.\n",
645
                    func, file, line, cond);
646 0
                break;
647
        case VAS_INCOMPLETE:
648 0
                VSB_printf(pan_vsb,
649
                    "Incomplete code in %s(), %s line %d:\n",
650
                    func, file, line);
651 0
                break;
652
        default:
653
        case VAS_ASSERT:
654 3
                VSB_printf(pan_vsb,
655
                    "Assert error in %s(), %s line %d:\n"
656
                    "  Condition(%s) not true.\n",
657
                    func, file, line, cond);
658 3
                break;
659
        }
660 18
        VSB_printf(pan_vsb, "version = %s, vrt api = %u.%u\n",
661
            VCS_version, VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
662 18
        VSB_printf(pan_vsb, "ident = %s,%s\n",
663
            heritage.ident, Waiter_GetName());
664 18
        VSB_printf(pan_vsb, "now = %f (mono), %f (real)\n",
665
            VTIM_mono(), VTIM_real());
666
667 18
        pan_backtrace(pan_vsb);
668
669 18
        if (err)
670 0
                VSB_printf(pan_vsb, "errno = %d (%s)\n", err, strerror(err));
671
672 18
        q = THR_GetName();
673 18
        if (q != NULL)
674 18
                VSB_printf(pan_vsb, "thread = (%s)\n", q);
675
676 18
        if (!FEATURE(FEATURE_SHORT_PANIC)) {
677 18
                req = THR_GetRequest();
678 18
                VSB_cat(pan_vsb, "thr.");
679 18
                pan_req(pan_vsb, req);
680 18
                if (req != NULL)
681 12
                        VSL_Flush(req->vsl, 0);
682 18
                bo = THR_GetBusyobj();
683 18
                VSB_cat(pan_vsb, "thr.");
684 18
                pan_busyobj(pan_vsb, bo);
685 18
                if (bo != NULL)
686 3
                        VSL_Flush(bo->vsl, 0);
687
        } else {
688 0
                VSB_printf(pan_vsb,
689
                    "Feature short panic supressed details.\n");
690
        }
691 18
        VSB_printf(pan_vsb, "\n");
692 18
        VSB_putc(pan_vsb, '\0');        /* NUL termination */
693
694 18
        if (FEATURE(FEATURE_NO_COREDUMP))
695 18
                exit(4);
696
        else
697 0
                abort();
698
}
699
700
/*--------------------------------------------------------------------*/
701
702
static void v_matchproto_(cli_func_t)
703 3
ccf_panic(struct cli *cli, const char * const *av, void *priv)
704
{
705
706
        (void)cli;
707
        (void)av;
708 3
        AZ(priv);
709 3
        AZ(strcmp("", "You asked for it"));
710
}
711
712
/*--------------------------------------------------------------------*/
713
714
static struct cli_proto debug_cmds[] = {
715
        { CLICMD_DEBUG_PANIC_WORKER,            "d",    ccf_panic },
716
        { NULL }
717
};
718
719
/*--------------------------------------------------------------------*/
720
721
void
722 2055
PAN_Init(void)
723
{
724
725 2055
        AZ(pthread_mutex_init(&panicstr_mtx, NULL));
726 2055
        VAS_Fail_Func = pan_ic;
727 2055
        pan_vsb = &pan_vsb_storage;
728 2055
        AN(heritage.panic_str);
729 2055
        AN(heritage.panic_str_len);
730 2055
        AN(VSB_new(pan_vsb, heritage.panic_str, heritage.panic_str_len,
731
            VSB_FIXEDLEN));
732 2055
        VSB_printf(pan_vsb, "This is a test\n");
733 2055
        AZ(VSB_finish(pan_vsb));
734 2055
        VSB_clear(pan_vsb);
735 2055
        heritage.panic_str[0] = '\0';
736 2055
        CLI_AddFuncs(debug_cmds);
737 2055
}