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