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