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