]> git.ipfire.org Git - thirdparty/squid.git/blame - src/debug.cc
Bug 2650: configure requires epoll_ctl in libepoll when --enable-epoll used
[thirdparty/squid.git] / src / debug.cc
CommitLineData
30a4f2a8 1/*
262a0e14 2 * $Id$
30a4f2a8 3 *
4 * DEBUG: section 0 Debug Routines
5 * AUTHOR: Harvest Derived
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
30a4f2a8 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
26ac0430 23 *
30a4f2a8 24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
26ac0430 28 *
30a4f2a8 29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
30a4f2a8 33 */
5b6f3fe5 34
351e769c 35#include "config.h"
ebe96adf 36#include "Debug.h"
608391f4 37#include "SquidTime.h"
62493678 38#include "util.h"
c772f001 39
62493678
AJ
40/* for shutting_down flag in xassert() */
41#include "globals.h"
e1f7507e 42
62493678
AJ
43/* cope with no squid.h */
44#ifndef MAXPATHLEN
45#define MAXPATHLEN 256
46#endif
47
48char *Debug::debugOptions = NULL;
49int Debug::override_X = 0;
50int Debug::log_stderr = -1;
51bool Debug::log_syslog = false;
c772f001 52int Debug::Levels[MAX_DEBUG_SECTIONS];
53int Debug::level;
62493678
AJ
54char *Debug::cache_log = NULL;
55int Debug::rotateNumber = 1;
f76d2f97 56FILE *debug_log = NULL;
090089c4 57static char *debug_log_file = NULL;
123abbe1 58static int Ctx_Lock = 0;
12858c3a 59static const char *debugLogTime(void);
2d72d4fd 60static void ctx_print(void);
811ef305 61#if HAVE_SYSLOG
5e6d4736 62#ifdef LOG_LOCAL4
63static int syslog_facility = 0;
64#endif
811ef305 65static void _db_print_syslog(const char *format, va_list args);
66#endif
67static void _db_print_stderr(const char *format, va_list args);
68static void _db_print_file(const char *format, va_list args);
24382924 69
1bc874d7 70#ifdef _SQUID_MSWIN_
71SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
72typedef BOOL (WINAPI * PFInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION, DWORD);
1bc874d7 73#endif
74
b8d8561b 75void
a3d5953d 76_db_print(const char *format,...)
090089c4 77{
62493678 78 char f[BUFSIZ]; f[0]='\0';
cd11dce6 79 va_list args1;
cd11dce6 80 va_list args2;
81 va_list args3;
8d707f3d 82
1bc874d7 83#ifdef _SQUID_MSWIN_
84 /* Multiple WIN32 threads may call this simultaneously */
85
26ac0430 86 if (!dbg_mutex) {
1bc874d7 87 HMODULE krnl_lib = GetModuleHandle("Kernel32");
88 PFInitializeCriticalSectionAndSpinCount InitializeCriticalSectionAndSpinCount = NULL;
89
90 if (krnl_lib)
91 InitializeCriticalSectionAndSpinCount =
92 (PFInitializeCriticalSectionAndSpinCount) GetProcAddress(krnl_lib,
93 "InitializeCriticalSectionAndSpinCount");
94
95 dbg_mutex = static_cast<CRITICAL_SECTION*>(xcalloc(1, sizeof(CRITICAL_SECTION)));
96
97 if (InitializeCriticalSectionAndSpinCount) {
98 /* let multiprocessor systems EnterCriticalSection() fast */
99
100 if (!InitializeCriticalSectionAndSpinCount(dbg_mutex, 4000)) {
101 if (debug_log) {
102 fprintf(debug_log, "FATAL: _db_print: can't initialize critical section\n");
103 fflush(debug_log);
104 }
105
106 fprintf(stderr, "FATAL: _db_print: can't initialize critical section\n");
107 abort();
108 } else
109 InitializeCriticalSection(dbg_mutex);
110 }
111 }
112
113 EnterCriticalSection(dbg_mutex);
380de6f3 114#endif
62e76326 115
8d707f3d 116 /* give a chance to context-based debugging to print current context */
380de6f3 117 if (!Ctx_Lock)
62e76326 118 ctx_print();
119
cd11dce6 120 va_start(args1, format);
121 va_start(args2, format);
122 va_start(args3, format);
62e76326 123
811ef305 124 snprintf(f, BUFSIZ, "%s| %s",
12858c3a 125 debugLogTime(),
62e76326 126 format);
127
cd11dce6 128 _db_print_file(f, args1);
129 _db_print_stderr(f, args2);
62e76326 130
811ef305 131#if HAVE_SYSLOG
cd11dce6 132 _db_print_syslog(format, args3);
133#endif
1bc874d7 134
8d707f3d 135#ifdef _SQUID_MSWIN_
1bc874d7 136 LeaveCriticalSection(dbg_mutex);
1bc874d7 137#endif
62e76326 138
cd11dce6 139 va_end(args1);
cd11dce6 140 va_end(args2);
141 va_end(args3);
811ef305 142}
74946a0f 143
811ef305 144static void
af6a12ee
AJ
145_db_print_file(const char *format, va_list args)
146{
74946a0f 147 if (debug_log == NULL)
62e76326 148 return;
149
123abbe1 150 /* give a chance to context-based debugging to print current context */
151 if (!Ctx_Lock)
62e76326 152 ctx_print();
153
811ef305 154 vfprintf(debug_log, format, args);
26ac0430 155 fflush(debug_log);
090089c4 156}
157
811ef305 158static void
af6a12ee
AJ
159_db_print_stderr(const char *format, va_list args)
160{
62493678 161 if (Debug::log_stderr < Debug::level)
62e76326 162 return;
163
811ef305 164 if (debug_log == stderr)
62e76326 165 return;
166
811ef305 167 vfprintf(stderr, format, args);
168}
169
170#if HAVE_SYSLOG
171static void
af6a12ee
AJ
172_db_print_syslog(const char *format, va_list args)
173{
811ef305 174 /* level 0,1 go to syslog */
62e76326 175
c772f001 176 if (Debug::level > 1)
62e76326 177 return;
178
62493678 179 if (!Debug::log_syslog)
62e76326 180 return;
181
62493678 182 char tmpbuf[BUFSIZ];
811ef305 183 tmpbuf[0] = '\0';
62e76326 184
811ef305 185 vsnprintf(tmpbuf, BUFSIZ, format, args);
62e76326 186
811ef305 187 tmpbuf[BUFSIZ - 1] = '\0';
62e76326 188
c772f001 189 syslog(Debug::level == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
811ef305 190}
191#endif /* HAVE_SYSLOG */
192
b8d8561b 193static void
af6a12ee
AJ
194debugArg(const char *arg)
195{
c9f06944 196 int s = 0;
197 int l = 0;
198 int i;
62e76326 199
62493678
AJ
200 if (!strncasecmp(arg, "rotate=", 7)) {
201 arg += 7;
202 Debug::rotateNumber = atoi(arg);
203 return;
204 } else if (!strncasecmp(arg, "ALL", 3)) {
62e76326 205 s = -1;
206 arg += 4;
c9f06944 207 } else {
62e76326 208 s = atoi(arg);
3d0ac046 209 while (*arg && *arg++ != ',');
c9f06944 210 }
62e76326 211
c9f06944 212 l = atoi(arg);
b6a2f15e 213 assert(s >= -1);
e879923e 214
26ac0430 215 if (s >= MAX_DEBUG_SECTIONS)
e879923e 216 s = MAX_DEBUG_SECTIONS-1;
62e76326 217
b6a2f15e 218 if (l < 0)
62e76326 219 l = 0;
220
b6a2f15e 221 if (l > 10)
62e76326 222 l = 10;
223
c9f06944 224 if (s >= 0) {
62e76326 225 Debug::Levels[s] = l;
226 return;
c9f06944 227 }
62e76326 228
c9f06944 229 for (i = 0; i < MAX_DEBUG_SECTIONS; i++)
62e76326 230 Debug::Levels[i] = l;
12b9e9b1 231}
232
b8d8561b 233static void
af6a12ee
AJ
234debugOpenLog(const char *logfile)
235{
ccff9601 236 if (logfile == NULL) {
62e76326 237 debug_log = stderr;
238 return;
ccff9601 239 }
62e76326 240
ccff9601 241 if (debug_log_file)
62e76326 242 xfree(debug_log_file);
243
ccff9601 244 debug_log_file = xstrdup(logfile); /* keep a static copy */
62e76326 245
f2cc1af5 246 if (debug_log && debug_log != stderr)
62e76326 247 fclose(debug_log);
248
ccff9601 249 debug_log = fopen(logfile, "a+");
62e76326 250
ccff9601 251 if (!debug_log) {
62e76326 252 fprintf(stderr, "WARNING: Cannot write log file: %s\n", logfile);
253 perror(logfile);
254 fprintf(stderr, " messages will be sent to 'stderr'.\n");
255 fflush(stderr);
256 debug_log = stderr;
ccff9601 257 }
62e76326 258
ec4daaa5 259#ifdef _SQUID_WIN32_
c4aefe96 260 setmode(fileno(debug_log), O_TEXT);
62e76326 261
c4aefe96 262#endif
ccff9601 263}
264
5e6d4736 265#if HAVE_SYSLOG
266#ifdef LOG_LOCAL4
267
268static struct syslog_facility_name {
269 const char *name;
270 int facility;
271}
272
273syslog_facility_names[] = {
274
275#ifdef LOG_AUTH
26ac0430
AJ
276 {
277 "auth", LOG_AUTH
278 },
5e6d4736 279#endif
280#ifdef LOG_AUTHPRIV
26ac0430
AJ
281 {
282 "authpriv", LOG_AUTHPRIV
283 },
5e6d4736 284#endif
285#ifdef LOG_CRON
26ac0430
AJ
286 {
287 "cron", LOG_CRON
288 },
5e6d4736 289#endif
290#ifdef LOG_DAEMON
26ac0430
AJ
291 {
292 "daemon", LOG_DAEMON
293 },
5e6d4736 294#endif
295#ifdef LOG_FTP
26ac0430
AJ
296 {
297 "ftp", LOG_FTP
298 },
5e6d4736 299#endif
300#ifdef LOG_KERN
26ac0430
AJ
301 {
302 "kern", LOG_KERN
303 },
5e6d4736 304#endif
305#ifdef LOG_LPR
26ac0430
AJ
306 {
307 "lpr", LOG_LPR
308 },
5e6d4736 309#endif
310#ifdef LOG_MAIL
26ac0430
AJ
311 {
312 "mail", LOG_MAIL
313 },
5e6d4736 314#endif
315#ifdef LOG_NEWS
26ac0430
AJ
316 {
317 "news", LOG_NEWS
318 },
5e6d4736 319#endif
320#ifdef LOG_SYSLOG
26ac0430
AJ
321 {
322 "syslog", LOG_SYSLOG
323 },
5e6d4736 324#endif
325#ifdef LOG_USER
26ac0430
AJ
326 {
327 "user", LOG_USER
328 },
5e6d4736 329#endif
330#ifdef LOG_UUCP
26ac0430
AJ
331 {
332 "uucp", LOG_UUCP
333 },
5e6d4736 334#endif
335#ifdef LOG_LOCAL0
26ac0430
AJ
336 {
337 "local0", LOG_LOCAL0
338 },
5e6d4736 339#endif
340#ifdef LOG_LOCAL1
26ac0430
AJ
341 {
342 "local1", LOG_LOCAL1
343 },
5e6d4736 344#endif
345#ifdef LOG_LOCAL2
26ac0430
AJ
346 {
347 "local2", LOG_LOCAL2
348 },
5e6d4736 349#endif
350#ifdef LOG_LOCAL3
26ac0430
AJ
351 {
352 "local3", LOG_LOCAL3
353 },
5e6d4736 354#endif
355#ifdef LOG_LOCAL4
26ac0430
AJ
356 {
357 "local4", LOG_LOCAL4
358 },
5e6d4736 359#endif
360#ifdef LOG_LOCAL5
26ac0430
AJ
361 {
362 "local5", LOG_LOCAL5
363 },
5e6d4736 364#endif
365#ifdef LOG_LOCAL6
26ac0430
AJ
366 {
367 "local6", LOG_LOCAL6
368 },
5e6d4736 369#endif
370#ifdef LOG_LOCAL7
26ac0430
AJ
371 {
372 "local7", LOG_LOCAL7
373 },
5e6d4736 374#endif
26ac0430
AJ
375 {
376 NULL, 0
377 }
378};
5e6d4736 379
380#endif
381
382void
af6a12ee
AJ
383_db_set_syslog(const char *facility)
384{
62493678
AJ
385 Debug::log_syslog = true;
386
5e6d4736 387#ifdef LOG_LOCAL4
388#ifdef LOG_DAEMON
389
390 syslog_facility = LOG_DAEMON;
391#else
392
393 syslog_facility = LOG_LOCAL4;
62493678 394#endif /* LOG_DAEMON */
5e6d4736 395
396 if (facility) {
397
398 struct syslog_facility_name *n;
399
400 for (n = syslog_facility_names; n->name; n++) {
401 if (strcmp(n->name, facility) == 0) {
402 syslog_facility = n->facility;
403 return;
404 }
405 }
406
407 fprintf(stderr, "unknown syslog facility '%s'\n", facility);
408 exit(1);
409 }
410
411#else
412 if (facility)
413 fprintf(stderr, "syslog facility type not supported on your system\n");
414
62493678 415#endif /* LOG_LOCAL4 */
5e6d4736 416}
417
418#endif
419
b8d8561b 420void
af6a12ee
AJ
421Debug::parseOptions(char const *options)
422{
12b9e9b1 423 int i;
424 char *p = NULL;
425 char *s = NULL;
090089c4 426
62493678 427 if (override_X) {
37296f4c 428 debugs(0, 9, "command-line -X overrides: " << options);
429 return;
430 }
431
12b9e9b1 432 for (i = 0; i < MAX_DEBUG_SECTIONS; i++)
fb6a61d1 433 Debug::Levels[i] = 0;
090089c4 434
30a4f2a8 435 if (options) {
62e76326 436 p = xstrdup(options);
437
438 for (s = strtok(p, w_space); s; s = strtok(NULL, w_space))
439 debugArg(s);
440
441 xfree(p);
12b9e9b1 442 }
d9e04dc7 443}
444
445void
af6a12ee
AJ
446_db_init(const char *logfile, const char *options)
447{
d9e04dc7 448 Debug::parseOptions(options);
62e76326 449
ccff9601 450 debugOpenLog(logfile);
090089c4 451
30a4f2a8 452#if HAVE_SYSLOG && defined(LOG_LOCAL4)
62e76326 453
62493678 454 if (Debug::log_syslog)
7dbca7a4 455 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);
62e76326 456
db40ae20 457#endif /* HAVE_SYSLOG */
458
090089c4 459}
460
b8d8561b 461void
af6a12ee
AJ
462_db_rotate_log(void)
463{
090089c4 464 if (debug_log_file == NULL)
62e76326 465 return;
466
71d95578 467#ifdef S_ISREG
62493678 468 struct stat sb;
2edc2504 469 if (stat(debug_log_file, &sb) == 0)
62e76326 470 if (S_ISREG(sb.st_mode) == 0)
471 return;
71d95578 472#endif
090089c4 473
62493678
AJ
474 char from[MAXPATHLEN];
475 from[0] = '\0';
476
477 char to[MAXPATHLEN];
478 to[0] = '\0';
479
1f38f50a 480 /*
481 * NOTE: we cannot use xrename here without having it in a
482 * separate file -- tools.c has too many dependencies to be
483 * used everywhere debug.c is used.
484 */
090089c4 485 /* Rotate numbers 0 through N up one */
62493678 486 for (int i = Debug::rotateNumber; i > 1;) {
62e76326 487 i--;
488 snprintf(from, MAXPATHLEN, "%s.%d", debug_log_file, i - 1);
489 snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, i);
0ef0f1de 490#ifdef _SQUID_MSWIN_
62e76326 491 remove
26ac0430 492 (to);
0ef0f1de 493#endif
62e76326 494 rename(from, to);
090089c4 495 }
62e76326 496
497 /*
498 * You can't rename open files on Microsoft "operating systems"
499 * so we close before renaming.
500 */
e24070c5 501#ifdef _SQUID_MSWIN_
502 if (debug_log != stderr)
62e76326 503 fclose(debug_log);
e24070c5 504#endif
090089c4 505 /* Rotate the current log to .0 */
62493678 506 if (Debug::rotateNumber > 0) {
62e76326 507 snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, 0);
0ef0f1de 508#ifdef _SQUID_MSWIN_
62e76326 509 remove
26ac0430 510 (to);
0ef0f1de 511#endif
62e76326 512 rename(debug_log_file, to);
090089c4 513 }
62e76326 514
090089c4 515 /* Close and reopen the log. It may have been renamed "manually"
516 * before HUP'ing us. */
0a8020d1 517 if (debug_log != stderr)
62493678 518 debugOpenLog(Debug::cache_log);
090089c4 519}
4873d3a4 520
521static const char *
af6a12ee
AJ
522debugLogTime(void)
523{
12858c3a 524
525 time_t t = getCurrentTime();
62e76326 526
4873d3a4 527 struct tm *tm;
528 static char buf[128];
529 static time_t last_t = 0;
62e76326 530
12858c3a 531 if (Debug::level > 1) {
532 char buf2[128];
533 tm = localtime(&t);
534 strftime(buf2, 127, "%Y/%m/%d %H:%M:%S", tm);
535 buf2[127] = '\0';
536 snprintf(buf, 127, "%s.%03d", buf2, (int) current_time.tv_usec / 1000);
537 last_t = t;
538 } else if (t != last_t) {
62e76326 539 tm = localtime(&t);
540 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
541 last_t = t;
4873d3a4 542 }
62e76326 543
12858c3a 544 buf[127] = '\0';
4873d3a4 545 return buf;
546}
547
bb71ea1f 548void
af6a12ee
AJ
549xassert(const char *msg, const char *file, int line)
550{
bf8fe701 551 debugs(0, 0, "assertion failed: " << file << ":" << line << ": \"" << msg << "\"");
62e76326 552
bb71ea1f 553 if (!shutting_down)
62e76326 554 abort();
bb71ea1f 555}
556
123abbe1 557/*
558 * Context-based Debugging
26970499 559 *
560 * Rationale
561 * ---------
26ac0430 562 *
26970499 563 * When you have a long nested processing sequence, it is often impossible
564 * for low level routines to know in what larger context they operate. If a
565 * routine coredumps, one can restore the context using debugger trace.
566 * However, in many case you do not want to coredump, but just want to report
567 * a potential problem. A report maybe useless out of problem context.
26ac0430 568 *
26970499 569 * To solve this potential problem, use the following approach:
26ac0430 570 *
26970499 571 * int
572 * top_level_foo(const char *url)
573 * {
574 * // define current context
575 * // note: we stack but do not dup ctx descriptions!
576 * Ctx ctx = ctx_enter(url);
577 * ...
578 * // go down; middle_level_bar will eventually call bottom_level_boo
579 * middle_level_bar(method, protocol);
580 * ...
581 * // exit, clean after yourself
582 * ctx_exit(ctx);
583 * }
26ac0430 584 *
26970499 585 * void
586 * bottom_level_boo(int status, void *data)
587 * {
588 * // detect exceptional condition, and simply report it, the context
589 * // information will be available somewhere close in the log file
590 * if (status == STRANGE_STATUS)
bf8fe701 591 * debugs(13, 6, "DOS attack detected, data: " << data);
26970499 592 * ...
593 * }
26ac0430 594 *
26970499 595 * Current implementation is extremely simple but still very handy. It has a
596 * negligible overhead (descriptions are not duplicated).
26ac0430 597 *
26970499 598 * When the _first_ debug message for a given context is printed, it is
599 * prepended with the current context description. Context is printed with
600 * the same debugging level as the original message.
26ac0430 601 *
26970499 602 * Note that we do not print context every type you do ctx_enter(). This
603 * approach would produce too many useless messages. For the same reason, a
604 * context description is printed at most _once_ even if you have 10
605 * debugging messages within one context.
26ac0430 606 *
26970499 607 * Contexts can be nested, of course. You must use ctx_enter() to enter a
608 * context (push it onto stack). It is probably safe to exit several nested
609 * contexts at _once_ by calling ctx_exit() at the top level (this will pop
610 * all context till current one). However, as in any stack, you cannot start
611 * in the middle.
26ac0430
AJ
612 *
613 * Analysis:
26970499 614 * i) locate debugging message,
615 * ii) locate current context by going _upstream_ in your log file,
616 * iii) hack away.
617 *
618 *
26ac0430 619 * To-Do:
26970499 620 * -----
621 *
123abbe1 622 * decide if we want to dup() descriptions (adds overhead) but allows to
623 * add printf()-style interface
26970499 624 *
2ac76861 625 * implementation:
26970499 626 * ---------------
2ac76861 627 *
123abbe1 628 * descriptions for contexts over CTX_MAX_LEVEL limit are ignored, you probably
629 * have a bug if your nesting goes that deep.
630 */
2ac76861 631
123abbe1 632#define CTX_MAX_LEVEL 255
2ac76861 633
634/*
635 * produce a warning when nesting reaches this level and then double
636 * the level
637 */
638static int Ctx_Warn_Level = 32;
123abbe1 639/* all descriptions has been printed up to this level */
a3f9588e 640static int Ctx_Reported_Level = -1;
123abbe1 641/* descriptions are still valid or active up to this level */
a3f9588e 642static int Ctx_Valid_Level = -1;
123abbe1 643/* current level, the number of nested ctx_enter() calls */
a3f9588e 644static int Ctx_Current_Level = -1;
123abbe1 645/* saved descriptions (stack) */
2ac76861 646static const char *Ctx_Descrs[CTX_MAX_LEVEL + 1];
b70d1c58 647/* "safe" get secription */
648static const char *ctx_get_descr(Ctx ctx);
123abbe1 649
650
651Ctx
af6a12ee
AJ
652ctx_enter(const char *descr)
653{
123abbe1 654 Ctx_Current_Level++;
655
656 if (Ctx_Current_Level <= CTX_MAX_LEVEL)
62e76326 657 Ctx_Descrs[Ctx_Current_Level] = descr;
123abbe1 658
659 if (Ctx_Current_Level == Ctx_Warn_Level) {
bf8fe701 660 debugs(0, 0, "# ctx: suspiciously deep (" << Ctx_Warn_Level << ") nesting:");
62e76326 661 Ctx_Warn_Level *= 2;
123abbe1 662 }
62e76326 663
123abbe1 664 return Ctx_Current_Level;
665}
666
667void
af6a12ee
AJ
668ctx_exit(Ctx ctx)
669{
123abbe1 670 assert(ctx >= 0);
2ac76861 671 Ctx_Current_Level = (ctx >= 0) ? ctx - 1 : -1;
62e76326 672
123abbe1 673 if (Ctx_Valid_Level > Ctx_Current_Level)
62e76326 674 Ctx_Valid_Level = Ctx_Current_Level;
123abbe1 675}
676
677/*
678 * the idea id to print each context description at most once but provide enough
679 * info for deducing the current execution stack
680 */
681static void
af6a12ee
AJ
682ctx_print(void)
683{
123abbe1 684 /* lock so _db_print will not call us recursively */
685 Ctx_Lock++;
686 /* ok, user saw [0,Ctx_Reported_Level] descriptions */
687 /* first inform about entries popped since user saw them */
62e76326 688
123abbe1 689 if (Ctx_Valid_Level < Ctx_Reported_Level) {
62e76326 690 if (Ctx_Reported_Level != Ctx_Valid_Level + 1)
691 _db_print("ctx: exit levels from %2d down to %2d\n",
692 Ctx_Reported_Level, Ctx_Valid_Level + 1);
693 else
694 _db_print("ctx: exit level %2d\n", Ctx_Reported_Level);
695
696 Ctx_Reported_Level = Ctx_Valid_Level;
123abbe1 697 }
62e76326 698
123abbe1 699 /* report new contexts that were pushed since last report */
700 while (Ctx_Reported_Level < Ctx_Current_Level) {
62e76326 701 Ctx_Reported_Level++;
702 Ctx_Valid_Level++;
703 _db_print("ctx: enter level %2d: '%s'\n", Ctx_Reported_Level,
704 ctx_get_descr(Ctx_Reported_Level));
123abbe1 705 }
62e76326 706
123abbe1 707 /* unlock */
708 Ctx_Lock--;
709}
b70d1c58 710
711/* checks for nulls and overflows */
712static const char *
af6a12ee
AJ
713ctx_get_descr(Ctx ctx)
714{
2ac76861 715 if (ctx < 0 || ctx > CTX_MAX_LEVEL)
62e76326 716 return "<lost>";
717
b70d1c58 718 return Ctx_Descrs[ctx] ? Ctx_Descrs[ctx] : "<null>";
719}
f95fe6ed 720
9eab365d 721int Debug::TheDepth = 0;
722
f95fe6ed 723std::ostream &
af6a12ee
AJ
724Debug::getDebugOut()
725{
9eab365d 726 assert(TheDepth >= 0);
727 ++TheDepth;
728 if (TheDepth > 1) {
729 assert(CurrentDebug);
730 *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{";
731 } else {
732 assert(!CurrentDebug);
733 CurrentDebug = new std::ostringstream();
734 // set default formatting flags
735 CurrentDebug->setf(std::ios::fixed);
736 CurrentDebug->precision(2);
737 }
4ecaa0f0 738 return *CurrentDebug;
f95fe6ed 739}
740
741void
af6a12ee
AJ
742Debug::finishDebug()
743{
9eab365d 744 assert(TheDepth >= 0);
745 assert(CurrentDebug);
746 if (TheDepth > 1) {
747 *CurrentDebug << "}-" << TheDepth << std::endl;
748 } else {
749 assert(TheDepth == 1);
750 _db_print("%s\n", CurrentDebug->str().c_str());
751 delete CurrentDebug;
752 CurrentDebug = NULL;
753 }
754 --TheDepth;
755}
756
757// Hack: replaces global ::xassert() to debug debugging assertions
758// Relies on assert macro calling xassert() without a specific scope.
759void
af6a12ee
AJ
760Debug::xassert(const char *msg, const char *file, int line)
761{
26ac0430 762
9eab365d 763 if (CurrentDebug) {
764 *CurrentDebug << "assertion failed: " << file << ":" << line <<
26ac0430 765 ": \"" << msg << "\"";
9eab365d 766 }
767 abort();
f95fe6ed 768}
769
bf5113eb 770std::ostringstream (*Debug::CurrentDebug)(NULL);
5b6f3fe5 771
af28bfbd
AJ
772const size_t
773BuildPrefixInit()
5b6f3fe5 774{
cd31e896 775 // XXX: This must be kept in sync with the actual debug.cc location
af28bfbd
AJ
776 const char *ThisFileNameTail = "src/debug.cc";
777
5b6f3fe5 778 const char *file=__FILE__;
cd31e896
AR
779
780 // Disable heuristic if it does not work.
781 if (!strstr(file, ThisFileNameTail))
af6a12ee 782 return 0;
cd31e896 783
af28bfbd 784 return strlen(file)-strlen(ThisFileNameTail);
5b6f3fe5 785}
af28bfbd
AJ
786
787const char*
788SkipBuildPrefix(const char* path)
5b6f3fe5 789{
af28bfbd
AJ
790 static const size_t BuildPrefixLength = BuildPrefixInit();
791
5b6f3fe5
FC
792 return path+BuildPrefixLength;
793}