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 7455
body_status_2str(enum body_status e)
69
{
70 7455
        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 20
reqbody_status_2str(enum req_body_state_e e)
82
{
83 20
        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 5
boc_state_2str(enum boc_state_e e)
95
{
96 5
        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 7015
sess_close_2str(enum sess_close sc, int want_desc)
108
{
109 7015
        switch (sc) {
110 25
        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 330
PAN_already(struct vsb *vsb, const void *ptr)
127
{
128
        int i;
129
130 330
        if (ptr == NULL) {
131 50
                VSB_printf(vsb, "},\n");
132 50
                return (1);
133
        }
134 1415
        for (i = 0; i < already_idx; i++) {
135 1190
                if (already_list[i] == ptr) {
136 55
                        VSB_printf(vsb, "  [Already dumped, see above]\n");
137 55
                        VSB_printf(vsb, "},\n");
138 55
                        return (1);
139
                }
140
        }
141 225
        if (already_idx < N_ALREADY)
142 225
                already_list[already_idx++] = ptr;
143 225
        return (0);
144
}
145
146
/*--------------------------------------------------------------------*/
147
148
static void
149 125
pan_ws(struct vsb *vsb, const struct ws *ws)
150
{
151
152 125
        VSB_printf(vsb, "ws = %p {\n", ws);
153 125
        if (PAN_already(vsb, ws))
154 60
                return;
155 65
        VSB_indent(vsb, 2);
156 65
        PAN_CheckMagic(vsb, ws, WS_MAGIC);
157 65
        if (ws->id[0] != '\0' && (!(ws->id[0] & 0x20)))
158 0
                VSB_printf(vsb, "OVERFLOWED ");
159 65
        VSB_printf(vsb, "id = \"%s\",\n", ws->id);
160 65
        VSB_printf(vsb, "{s, f, r, e} = {%p", ws->s);
161 65
        if (ws->f >= ws->s)
162 65
                VSB_printf(vsb, ", +%ld", (long) (ws->f - ws->s));
163
        else
164 0
                VSB_printf(vsb, ", %p", ws->f);
165 65
        if (ws->r >= ws->s)
166 0
                VSB_printf(vsb, ", +%ld", (long) (ws->r - ws->s));
167
        else
168 65
                VSB_printf(vsb, ", %p", ws->r);
169 65
        if (ws->e >= ws->s)
170 65
                VSB_printf(vsb, ", +%ld", (long) (ws->e - ws->s));
171
        else
172 0
                VSB_printf(vsb, ", %p", ws->e);
173 65
        VSB_printf(vsb, "},\n");
174 65
        VSB_indent(vsb, -2);
175 65
        VSB_printf(vsb, "},\n");
176
}
177
178
/*--------------------------------------------------------------------*/
179
180
static void
181 25
pan_htc(struct vsb *vsb, const struct http_conn *htc)
182
{
183
184 25
        VSB_printf(vsb, "http_conn = %p {\n", htc);
185 25
        if (PAN_already(vsb, htc))
186 0
                return;
187 25
        VSB_indent(vsb, 2);
188 25
        PAN_CheckMagic(vsb, htc, HTTP_CONN_MAGIC);
189 25
        if (htc->rfd != NULL)
190 20
                VSB_printf(vsb, "fd = %d (@%p),\n", *htc->rfd, htc->rfd);
191 25
        VSB_printf(vsb, "doclose = %s,\n", sess_close_2str(htc->doclose, 0));
192 25
        pan_ws(vsb, htc->ws);
193 25
        VSB_printf(vsb, "{rxbuf_b, rxbuf_e} = {%p, %p},\n",
194
            htc->rxbuf_b, htc->rxbuf_e);
195 25
        VSB_printf(vsb, "{pipeline_b, pipeline_e} = {%p, %p},\n",
196
            htc->pipeline_b, htc->pipeline_e);
197 25
        VSB_printf(vsb, "content_length = %jd,\n",
198 25
            (intmax_t)htc->content_length);
199 25
        VSB_printf(vsb, "body_status = %s,\n",
200
            body_status_2str(htc->body_status));
201 25
        VSB_printf(vsb, "first_byte_timeout = %f,\n",
202
            htc->first_byte_timeout);
203 25
        VSB_printf(vsb, "between_bytes_timeout = %f,\n",
204
            htc->between_bytes_timeout);
205 25
        VSB_indent(vsb, -2);
206 25
        VSB_printf(vsb, "},\n");
207
}
208
209
/*--------------------------------------------------------------------*/
210
211
static void
212 35
pan_http(struct vsb *vsb, const char *id, const struct http *h)
213
{
214
        int i;
215
216 35
        VSB_printf(vsb, "http[%s] = %p {\n", id, h);
217 35
        if (PAN_already(vsb, h))
218 0
                return;
219 35
        VSB_indent(vsb, 2);
220 35
        PAN_CheckMagic(vsb, h, HTTP_MAGIC);
221 35
        pan_ws(vsb, h->ws);
222 35
        VSB_printf(vsb, "hdrs {\n");
223 35
        VSB_indent(vsb, 2);
224 320
        for (i = 0; i < h->nhd; ++i) {
225 285
                if (h->hd[i].b == NULL && h->hd[i].e == NULL)
226 70
                        continue;
227 430
                VSB_printf(vsb, "\"%.*s\",\n",
228 430
                    (int)(h->hd[i].e - h->hd[i].b), h->hd[i].b);
229
        }
230 35
        VSB_indent(vsb, -2);
231 35
        VSB_printf(vsb, "},\n");
232 35
        VSB_indent(vsb, -2);
233 35
        VSB_printf(vsb, "},\n");
234
}
235
236
/*--------------------------------------------------------------------*/
237
static void
238 5
pan_boc(struct vsb *vsb, const struct boc *boc)
239
{
240 5
        VSB_printf(vsb, "boc = %p {\n", boc);
241 5
        if (PAN_already(vsb, boc))
242 0
                return;
243 5
        VSB_indent(vsb, 2);
244 5
        PAN_CheckMagic(vsb, boc, BOC_MAGIC);
245 5
        VSB_printf(vsb, "refcnt = %u,\n", boc->refcount);
246 5
        VSB_printf(vsb, "state = %s,\n", boc_state_2str(boc->state));
247 5
        VSB_printf(vsb, "vary = %p,\n", boc->vary);
248 5
        VSB_printf(vsb, "stevedore_priv = %p,\n", boc->stevedore_priv);
249 5
        VSB_indent(vsb, -2);
250 5
        VSB_printf(vsb, "},\n");
251
}
252
253
/*--------------------------------------------------------------------*/
254
255
static void
256 10
pan_objcore(struct vsb *vsb, const char *typ, const struct objcore *oc)
257
{
258
        const char *p;
259
260 10
        VSB_printf(vsb, "objcore[%s] = %p {\n", typ, oc);
261 10
        if (PAN_already(vsb, oc))
262 0
                return;
263 10
        VSB_indent(vsb, 2);
264 10
        PAN_CheckMagic(vsb, oc, OBJCORE_MAGIC);
265 10
        VSB_printf(vsb, "refcnt = %d,\n", oc->refcnt);
266 10
        VSB_printf(vsb, "flags = {");
267
268
/*lint -save -esym(438,p) -esym(838,p) -e539 */
269 10
        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 10
        VSB_printf(vsb, "},\n");
274 10
        VSB_printf(vsb, "exp_flags = {");
275 10
        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 10
        VSB_printf(vsb, "},\n");
281
282 10
        if (oc->boc != NULL)
283 5
                pan_boc(vsb, oc->boc);
284 30
        VSB_printf(vsb, "exp = {%f, %f, %f, %f},\n",
285 30
            oc->t_origin, oc->ttl, oc->grace, oc->keep);
286 10
        VSB_printf(vsb, "objhead = %p,\n", oc->objhead);
287 10
        VSB_printf(vsb, "stevedore = %p", oc->stobj->stevedore);
288 10
        if (oc->stobj->stevedore != NULL) {
289 5
                VSB_printf(vsb, " (%s", oc->stobj->stevedore->name);
290 5
                if (strlen(oc->stobj->stevedore->ident))
291 5
                        VSB_printf(vsb, " %s", oc->stobj->stevedore->ident);
292 5
                VSB_printf(vsb, ")");
293 5
                if (oc->stobj->stevedore->panic) {
294 5
                        VSB_printf(vsb, " {\n");
295 5
                        VSB_indent(vsb, 2);
296 5
                        oc->stobj->stevedore->panic(vsb, oc);
297 5
                        VSB_indent(vsb, -2);
298 5
                        VSB_printf(vsb, "}");
299
                }
300
        }
301 10
        VSB_printf(vsb, ",\n");
302 10
        VSB_indent(vsb, -2);
303 10
        VSB_printf(vsb, "},\n");
304
}
305
306
/*--------------------------------------------------------------------*/
307
308
static void
309 20
pan_wrk(struct vsb *vsb, const struct worker *wrk)
310
{
311
        const char *hand;
312
        unsigned m, u;
313
        const char *p;
314
315 20
        VSB_printf(vsb, "worker = %p {\n", wrk);
316 20
        if (PAN_already(vsb, wrk))
317 0
                return;
318 20
        VSB_indent(vsb, 2);
319 20
        PAN_CheckMagic(vsb, wrk, WORKER_MAGIC);
320 20
        pan_ws(vsb, wrk->aws);
321
322 20
        m = wrk->cur_method;
323 20
        VSB_printf(vsb, "VCL::method = ");
324 20
        if (m == 0) {
325 0
                VSB_printf(vsb, "none,\n");
326 0
                return;
327
        }
328 20
        if (!(m & 1))
329 20
                VSB_printf(vsb, "inside ");
330 20
        m &= ~1;
331 20
        hand = VCL_Method_Name(m);
332 20
        if (hand != NULL)
333 20
                VSB_printf(vsb, "%s,\n", hand);
334
        else
335 0
                VSB_printf(vsb, "0x%x,\n", m);
336
337 20
        hand = VCL_Return_Name(wrk->handling);
338 20
        if (hand != NULL)
339 0
                VSB_printf(vsb, "VCL::return = %s,\n", hand);
340
        else
341 20
                VSB_printf(vsb, "VCL::return = 0x%x,\n", wrk->handling);
342 20
        VSB_printf(vsb, "VCL::methods = {");
343 20
        m = wrk->seen_methods;
344 20
        p = "";
345 95
        for (u = 1; m ; u <<= 1) {
346 75
                if (m & u) {
347 35
                        VSB_printf(vsb, "%s%s", p, VCL_Method_Name(u));
348 35
                        m &= ~u;
349 35
                        p = ", ";
350
                }
351
        }
352 20
        VSB_printf(vsb, "},\n");
353 20
        VSB_indent(vsb, -2);
354 20
        VSB_printf(vsb, "},\n");
355
}
356
357
static void
358 5
pan_vfp(struct vsb *vsb, const struct vfp_ctx *vfc)
359
{
360
        struct vfp_entry *vfe;
361
362 5
        VSB_printf(vsb, "vfc = %p {\n", vfc);
363 5
        VSB_indent(vsb, 2);
364 5
        VSB_printf(vsb, "failed = %d,\n", vfc->failed);
365 5
        VSB_printf(vsb, "req = %p,\n", vfc->req);
366 5
        VSB_printf(vsb, "resp = %p,\n", vfc->resp);
367 5
        VSB_printf(vsb, "wrk = %p,\n", vfc->wrk);
368 5
        VSB_printf(vsb, "oc = %p,\n", vfc->oc);
369
370 5
        if (!VTAILQ_EMPTY(&vfc->vfp)) {
371 5
                VSB_printf(vsb, "filters = {\n");
372 5
                VSB_indent(vsb, 2);
373 10
                VTAILQ_FOREACH(vfe, &vfc->vfp, list) {
374 5
                        VSB_printf(vsb, "%s = %p {\n",
375 5
                                   vfe->vfp->name, vfe);
376 5
                        VSB_indent(vsb, 2);
377 5
                        VSB_printf(vsb, "priv1 = %p,\n", vfe->priv1);
378 5
                        VSB_printf(vsb, "priv2 = %zd,\n", vfe->priv2);
379 5
                        VSB_printf(vsb, "closed = %d\n", vfe->closed);
380 5
                        VSB_indent(vsb, -2);
381 5
                        VSB_printf(vsb, "},\n");
382
                }
383 5
                VSB_indent(vsb, -2);
384 5
                VSB_printf(vsb, "},\n");
385
        }
386
387 5
        VSB_printf(vsb, "obj_flags = 0x%x,\n", vfc->obj_flags);
388 5
        VSB_indent(vsb, -2);
389 5
        VSB_printf(vsb, "},\n");
390 5
}
391
392
393
static void
394 35
pan_busyobj(struct vsb *vsb, const struct busyobj *bo)
395
{
396
        const char *p;
397
398 35
        VSB_printf(vsb, "busyobj = %p {\n", bo);
399 35
        if (PAN_already(vsb, bo))
400 30
                return;
401 5
        VSB_indent(vsb, 2);
402 5
        PAN_CheckMagic(vsb, bo, BUSYOBJ_MAGIC);
403 5
        pan_ws(vsb, bo->ws);
404 5
        VSB_printf(vsb, "retries = %d, ", bo->retries);
405 5
        VSB_printf(vsb, "flags = {");
406 5
        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 5
        VSB_printf(vsb, "},\n");
413
414 5
        if (VALID_OBJ(bo->htc, HTTP_CONN_MAGIC))
415 5
                pan_htc(vsb, bo->htc);
416
417 5
        if (bo->vfc)
418 5
                pan_vfp(vsb, bo->vfc);
419
420 5
        VDI_Panic(bo->director_req, vsb, "director_req");
421 5
        if (bo->director_resp == bo->director_req)
422 5
                VSB_printf(vsb, "director_resp = director_req,\n");
423
        else
424 0
                VDI_Panic(bo->director_resp, vsb, "director_resp");
425 5
        if (bo->bereq != NULL && bo->bereq->ws != NULL)
426 5
                pan_http(vsb, "bereq", bo->bereq);
427 5
        if (bo->beresp != NULL && bo->beresp->ws != NULL)
428 5
                pan_http(vsb, "beresp", bo->beresp);
429 5
        if (bo->fetch_objcore)
430 5
                pan_objcore(vsb, "fetch", bo->fetch_objcore);
431 5
        if (bo->stale_oc)
432 0
                pan_objcore(vsb, "ims", bo->stale_oc);
433 5
        VCL_Panic(vsb, bo->vcl);
434 5
        VMOD_Panic(vsb);
435 5
        VSB_indent(vsb, -2);
436 5
        VSB_printf(vsb, "},\n");
437
}
438
439
/*--------------------------------------------------------------------*/
440
441
static void
442 35
pan_req(struct vsb *vsb, const struct req *req)
443
{
444
        const char *stp;
445
        const struct transport *xp;
446
447 35
        VSB_printf(vsb, "req = %p {\n", req);
448 35
        if (PAN_already(vsb, req))
449 15
                return;
450 20
        VSB_indent(vsb, 2);
451 20
        PAN_CheckMagic(vsb, req, REQ_MAGIC);
452 20
        xp = req->transport;
453 20
        VSB_printf(vsb, "vxid = %u, transport = %s", VXID(req->vsl->wid),
454
            xp == NULL ? "NULL" : xp->name);
455
456 20
        if (xp != NULL && xp->req_panic != NULL) {
457 15
                VSB_printf(vsb, " {\n");
458 15
                VSB_indent(vsb, 2);
459 15
                xp->req_panic(vsb, req);
460 15
                VSB_indent(vsb, -2);
461 15
                VSB_printf(vsb, "}");
462
        }
463 20
        VSB_printf(vsb, "\n");
464 20
        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 20
        if (stp != NULL)
470 20
                VSB_printf(vsb, "step = %s,\n", stp);
471
        else
472 0
                VSB_printf(vsb, "step = 0x%x,\n", req->req_step);
473
474 20
        VSB_printf(vsb, "req_body = %s,\n",
475
            reqbody_status_2str(req->req_body_status));
476
477 20
        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 20
        VSB_printf(vsb, "restarts = %d, esi_level = %d,\n",
483
            req->restarts, req->esi_level);
484
485 20
        if (req->sp != NULL)
486 20
                pan_sess(vsb, req->sp);
487
488 20
        if (req->wrk != NULL)
489 20
                pan_wrk(vsb, req->wrk);
490
491 20
        pan_ws(vsb, req->ws);
492 20
        if (VALID_OBJ(req->htc, HTTP_CONN_MAGIC))
493 20
                pan_htc(vsb, req->htc);
494 20
        pan_http(vsb, "req", req->http);
495 20
        if (req->resp->ws != NULL)
496 5
                pan_http(vsb, "resp", req->resp);
497
498 20
        VCL_Panic(vsb, req->vcl);
499 20
        VMOD_Panic(vsb);
500
501 20
        if (req->body_oc != NULL)
502 0
                pan_objcore(vsb, "BODY", req->body_oc);
503 20
        if (req->objcore != NULL)
504 5
                pan_objcore(vsb, "REQ", req->objcore);
505
506 20
        VSB_printf(vsb, "flags = {\n");
507 20
        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 20
        VSB_indent(vsb, -2);
511 20
        VSB_printf(vsb, "},\n");
512
513 20
        pan_privs(vsb, req->privs);
514
515 20
        VSB_indent(vsb, -2);
516 20
        VSB_printf(vsb, "},\n");
517
}
518
519
/*--------------------------------------------------------------------*/
520
521
static void
522 20
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 20
        VSB_printf(vsb, "sp = %p {\n", sp);
529 20
        if (PAN_already(vsb, sp))
530 0
                return;
531 20
        VSB_indent(vsb, 2);
532 20
        PAN_CheckMagic(vsb, sp, SESS_MAGIC);
533 20
        xp = XPORT_ByNumber(sp->sattr[SA_TRANSPORT]);
534 20
        VSB_printf(vsb, "fd = %d, vxid = %u,\n",
535 20
            sp->fd, VXID(sp->vxid));
536 20
        VSB_printf(vsb, "t_open = %f,\n", sp->t_open);
537 20
        VSB_printf(vsb, "t_idle = %f,\n", sp->t_idle);
538 20
        pan_ws(vsb, sp->ws);
539 20
        VSB_printf(vsb, "transport = %s",
540
            xp == NULL ? "<none>" : xp->name);
541 20
        if (xp != NULL && xp->sess_panic != NULL) {
542 20
                VSB_printf(vsb, " {\n");
543 20
                VSB_indent(vsb, 2);
544 20
                xp->sess_panic(vsb, sp);
545 20
                VSB_indent(vsb, -2);
546 20
                VSB_printf(vsb, "}");
547
        }
548 20
        VSB_printf(vsb, "\n");
549 20
        ci = SES_Get_String_Attr(sp, SA_CLIENT_IP);
550 20
        cp = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
551 20
        if (VALID_OBJ(sp->listen_sock, LISTEN_SOCK_MAGIC))
552 20
                VSB_printf(vsb, "client = %s %s %s,\n", ci, cp,
553 20
                           sp->listen_sock->endpoint);
554
        else
555 0
                VSB_printf(vsb, "client = %s %s <unknown>\n", ci, cp);
556
557 20
        VSB_indent(vsb, -2);
558 20
        VSB_printf(vsb, "},\n");
559
}
560
561
/*--------------------------------------------------------------------*/
562
563
#define BACKTRACE_LEVELS        10
564
565
static void
566 35
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 35
        size = backtrace (array, BACKTRACE_LEVELS);
576 35
        if (size > BACKTRACE_LEVELS) {
577 0
                VSB_printf(vsb, "Backtrace not available (ret=%zu)\n", size);
578 0
                return;
579
        }
580 35
        VSB_printf(vsb, "Backtrace:\n");
581 35
        VSB_indent(vsb, 2);
582 300
        for (i = 0; i < size; i++) {
583 265
                bprintf(buf, "%p", array[i]);
584 265
                VSB_printf(vsb, "%s: ", buf);
585 265
                strings = backtrace_symbols(&array[i], 1);
586 265
                if (strings == NULL || strings[0] == NULL) {
587 0
                        VSB_printf(vsb, "(?)");
588
                } else {
589 265
                        p = strings[0];
590 265
                        if (!memcmp(buf, p, strlen(buf))) {
591 265
                                p += strlen(buf);
592 265
                                if (*p == ':')
593 0
                                        p++;
594 795
                                while (*p == ' ')
595 265
                                        p++;
596
                        }
597 265
                        VSB_printf(vsb, "%s", p);
598
                }
599 265
                VSB_printf (vsb, "\n");
600
        }
601 35
        VSB_indent(vsb, -2);
602
}
603
604
/*--------------------------------------------------------------------*/
605
606
static void __attribute__((__noreturn__))
607 35
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 35
        int err = errno;
615
616 35
        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 35
        memset(&sa, 0, sizeof sa);
626 35
        sa.sa_handler = SIG_DFL;
627 35
        (void)sigaction(SIGSEGV, &sa, NULL);
628
        /* Set SIGABRT back to default so the final abort() has the
629
           desired effect */
630 35
        (void)sigaction(SIGABRT, &sa, NULL);
631
632 35
        switch (kind) {
633
        case VAS_WRONG:
634 15
                VSB_printf(pan_vsb,
635
                    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
636 15
                break;
637
        case VAS_VCL:
638 15
                VSB_printf(pan_vsb,
639
                    "Panic from VCL:\n  %s\n", cond);
640 15
                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 5
                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 5
                break;
659
        }
660 35
        VSB_printf(pan_vsb, "version = %s, vrt api = %u.%u\n",
661
            VCS_version, VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
662 35
        VSB_printf(pan_vsb, "ident = %s,%s\n",
663
            heritage.ident, Waiter_GetName());
664 35
        VSB_printf(pan_vsb, "now = %f (mono), %f (real)\n",
665
            VTIM_mono(), VTIM_real());
666
667 35
        pan_backtrace(pan_vsb);
668
669 35
        if (err)
670 5
                VSB_printf(pan_vsb, "errno = %d (%s)\n", err, strerror(err));
671
672 35
        q = THR_GetName();
673 35
        if (q != NULL)
674 35
                VSB_printf(pan_vsb, "thread = (%s)\n", q);
675
676 35
        if (!FEATURE(FEATURE_SHORT_PANIC)) {
677 35
                req = THR_GetRequest();
678 35
                VSB_cat(pan_vsb, "thr.");
679 35
                pan_req(pan_vsb, req);
680 35
                if (req != NULL)
681 20
                        VSL_Flush(req->vsl, 0);
682 35
                bo = THR_GetBusyobj();
683 35
                VSB_cat(pan_vsb, "thr.");
684 35
                pan_busyobj(pan_vsb, bo);
685 35
                if (bo != NULL)
686 5
                        VSL_Flush(bo->vsl, 0);
687
        } else {
688 0
                VSB_printf(pan_vsb,
689
                    "Feature short panic supressed details.\n");
690
        }
691 35
        VSB_printf(pan_vsb, "\n");
692 35
        VSB_putc(pan_vsb, '\0');        /* NUL termination */
693
694 35
        if (FEATURE(FEATURE_NO_COREDUMP))
695 35
                exit(4);
696
        else
697 0
                abort();
698
}
699
700
/*--------------------------------------------------------------------*/
701
702
static void v_matchproto_(cli_func_t)
703 5
ccf_panic(struct cli *cli, const char * const *av, void *priv)
704
{
705
706
        (void)cli;
707
        (void)av;
708 5
        AZ(priv);
709 5
        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 3440
PAN_Init(void)
723
{
724
725 3440
        AZ(pthread_mutex_init(&panicstr_mtx, NULL));
726 3440
        VAS_Fail_Func = pan_ic;
727 3440
        pan_vsb = &pan_vsb_storage;
728 3440
        AN(heritage.panic_str);
729 3440
        AN(heritage.panic_str_len);
730 3440
        AN(VSB_new(pan_vsb, heritage.panic_str, heritage.panic_str_len,
731
            VSB_FIXEDLEN));
732 3440
        VSB_printf(pan_vsb, "This is a test\n");
733 3440
        AZ(VSB_finish(pan_vsb));
734 3440
        VSB_clear(pan_vsb);
735 3440
        heritage.panic_str[0] = '\0';
736 3440
        CLI_AddFuncs(debug_cmds);
737 3440
}