summaryrefslogtreecommitdiff
path: root/debug.cc
blob: 9b98b1f49c2a0f392d574a20d9fb4d1cd2fa638d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifdef USE_PCH
#include "pch.h"
#else
#include "debug.h"
#endif

#ifdef DEBUG_ENABLED

#ifndef USE_PCH
#include <map>
#include <fstream>

#include <unistd.h>		// for the `write' method
#endif

int offset = 0;

std::map<void *, int> ptrs;

#define PRINT_INC(x) {					\
  char buf[128];					\
  std::sprintf(buf, "%d: %p: %s", ++offset, ptr, x);	\
  write(1, buf, std::strlen(buf));			\
}

#define PRINT_DEC(x) {					\
  char buf[128];					\
  std::sprintf(buf, "%d: %p: %s", --offset, ptr, x);	\
  write(1, buf, std::strlen(buf));			\
}

void * operator new(std::size_t size) throw (std::bad_alloc) {
  void * ptr = std::malloc(size);
  if (DEBUG("debug.alloc")) {
    PRINT_INC("void * operator new(std::size_t size) throw (std::bad_alloc)\n");
  }
  return ptr;
}
void * operator new[](std::size_t size) throw (std::bad_alloc) {
  void * ptr = std::malloc(size);
  if (DEBUG("debug.alloc")) {
    PRINT_INC("void * operator new[](std::size_t) throw (std::bad_alloc)\n");
  }
  return ptr;
}
void * operator new(std::size_t size, const std::nothrow_t&) throw() {
  void * ptr = std::malloc(size);
  if (DEBUG("debug.alloc")) {
    PRINT_INC("void * operator new(std::size_t size, const std::nothrow_t&) throw()\n");
  }
  return ptr;
}
void * operator new[](std::size_t size, const std::nothrow_t&) throw() {
  void * ptr = std::malloc(size);
  if (DEBUG("debug.alloc")) {
    PRINT_INC("void * operator new[](std::size_t size, const std::nothrow_t&) throw()\n");
  }
  return ptr;
}
void   operator delete(void * ptr) throw() {
  if (DEBUG("debug.alloc")) {
    PRINT_DEC("void   operator delete(void * ptr) throw()\n");
  }
  std::free(ptr);
}
void   operator delete[](void * ptr) throw() {
  if (DEBUG("debug.alloc")) {
    PRINT_DEC("void   operator delete[](void * ptr) throw()\n");
  }
  std::free(ptr);
}
void   operator delete(void * ptr, const std::nothrow_t&) throw() {
  if (DEBUG("debug.alloc")) {
    PRINT_DEC("void   operator delete(void * ptr, const std::nothrow_t&) throw()\n");
  }
  std::free(ptr);
}
void   operator delete[](void * ptr, const std::nothrow_t&) throw() {
  if (DEBUG("debug.alloc")) {
    PRINT_DEC("void   operator delete[](void * ptr, const std::nothrow_t&) throw()\n");
  }
  std::free(ptr);
}

std::ostream * _debug_stream	  = &std::cerr;
bool	       _free_debug_stream = false;

bool _debug_active(const char * const cls) {
  if (char * debug = std::getenv("DEBUG_CLASS")) {
    static const char * error;
    static int	  erroffset;
    static int	  ovec[30];
    static pcre * class_regexp = pcre_compile(debug, PCRE_CASELESS,
					      &error, &erroffset, NULL);
    return pcre_exec(class_regexp, NULL, cls, std::strlen(cls),
		     0, 0, ovec, 30) >= 0;
  }
  return false;
}

static struct init_streams {
  init_streams() {
    // If debugging is enabled and DEBUG_FILE is set, all debugging
    // output goes to that file.
    if (const char * p = std::getenv("DEBUG_FILE")) {
      _debug_stream      = new std::ofstream(p);
      _free_debug_stream = true;
    }
  }
  ~init_streams() {
    if (_free_debug_stream && _debug_stream) {
      delete _debug_stream;
      _debug_stream = NULL;
    }
  }
} _debug_init;

#endif // DEBUG_ENABLED

#if DEBUG_LEVEL >= BETA

#ifndef USE_PCH
#include <string>
#endif

void debug_assert(const std::string& reason,
		  const std::string& file,
		  unsigned long      line)
{
  throw new fatal_assert(reason, new file_context(file, line));
}

#endif