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