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