ardour
boost_debug.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 Paul Davis
3  From an idea by Carl Hetherington.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "libpbd-config.h"
22 
23 #ifdef HAVE_EXECINFO
24 #include <execinfo.h>
25 #endif
26 
27 #include <stdlib.h>
28 #include <iostream>
29 #include <map>
30 #include <set>
31 #include <vector>
32 #include <glibmm/threads.h>
33 #include <boost/shared_ptr.hpp>
34 
35 #include "pbd/stacktrace.h"
36 #include "pbd/boost_debug.h"
37 
38 class Backtrace {
39 public:
40  Backtrace ();
41  std::ostream& print (std::ostream& str) const;
42 
43 private:
44  void* trace[200];
45  size_t size;
46 };
47 
48 std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
49 
50 
52 {
53 #ifdef HAVE_EXECINFO
54  size = ::backtrace (trace, 200);
55 #endif
56 }
57 
58 std::ostream&
59 Backtrace::print (std::ostream& str) const
60 {
61  char **strings = 0;
62  size_t i;
63 
64  if (size) {
65 #ifdef HAVE_EXECINFO
66  strings = ::backtrace_symbols (trace, size);
67 #endif
68  if (strings) {
69  for (i = 3; i < 5+18 && i < size; i++) {
70  str << strings[i] << std::endl;
71  }
72  free (strings);
73  }
74  }
75 
76  return str;
77 }
78 
79 struct BTPair {
80 
83 
84  BTPair (Backtrace* bt) : ref (bt), rel (0) {}
85  ~BTPair () { }
86 
87 };
88 
89 std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
90  str << "*********************************************\n";
91  if (btp.ref) str << *btp.ref << std::endl;
92  str << "Rel:\n";
93  if (btp.rel) str << *btp.rel << std::endl;
94  return str;
95 }
96 
97 struct SPDebug {
100 
101  SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
102  ~SPDebug () {
103  delete constructor;
104  delete destructor;
105  }
106 };
107 
108 std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
109 {
110  str << "Constructor :" << std::endl;
111  if (spd.constructor) {
112  str << *spd.constructor << std::endl;
113  }
114 
115  return str;
116 }
117 
118 typedef std::multimap<void const*,SPDebug*> PointerMap;
119 typedef std::map<void const*,const char*> IPointerMap;
120 
121 using namespace std;
122 
125  if (_sptrs == 0) {
126  _sptrs = new PointerMap;
127  }
128  return *_sptrs;
129 }
130 
133  if (_interesting_pointers == 0) {
135  }
136  return *_interesting_pointers;
137 }
138 
139 static Glib::Threads::Mutex* _the_lock;
140 static Glib::Threads::Mutex& the_lock() {
141  if (_the_lock == 0) {
142  _the_lock = new Glib::Threads::Mutex;
143  }
144  return *_the_lock;
145 }
146 
147 
148 static bool
149 is_interesting_object (void const* ptr)
150 {
151  if (ptr == 0) {
152  return false;
153  }
154 
155  return interesting_pointers().find (ptr) != interesting_pointers().end();
156 }
157 
158 /* ------------------------------- */
159 
160 static bool debug_out = false;
161 
162 void
164 {
165  debug_out = yn;
166 }
167 
168 void
169 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
170 {
172  pair<void*,const char*> newpair (ptr, type);
173  interesting_pointers().insert (newpair);
174  if (debug_out) {
175  cerr << "Interesting object @ " << ptr << " of type " << type << endl;
176  }
177 }
178 
179 void
180 boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
181 {
182  if (old_obj == 0 && obj == 0) {
183  return;
184  }
185 
187 
188  if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
189  if (debug_out) {
190  cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
191  }
192  }
193 
194  if (is_interesting_object (old_obj)) {
195  if (debug_out) {
196  cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
197  << " (total sp's = " << sptrs().size() << ')' << endl;
198  }
199  PointerMap::iterator x = sptrs().find (sp);
200 
201  if (x != sptrs().end()) {
202  sptrs().erase (x);
203  if (debug_out) {
204  cerr << "\tRemoved (by assignment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
205  }
206  }
207  }
208 
209  if (is_interesting_object (obj)) {
210 
211  pair<void const*, SPDebug*> newpair;
212 
213  newpair.first = sp;
214  newpair.second = new SPDebug (new Backtrace());
215 
216  sptrs().insert (newpair);
217 
218  if (debug_out) {
219  cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
220  << " UC = " << new_use_count
221  << " (total sp's = " << sptrs().size() << ')' << endl;
222  cerr << *newpair.second << endl;
223  }
224  }
225 }
226 
227 void
228 boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
229 {
230  if (old_obj == 0 && obj == 0) {
231  return;
232  }
233 
235 
236  if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
237  if (debug_out) {
238  cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
239  }
240  }
241 
242  if (is_interesting_object (old_obj)) {
243  if (debug_out) {
244  cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
245  << " (total sp's = " << sptrs().size() << ')' << endl;
246  }
247  PointerMap::iterator x = sptrs().find (sp);
248 
249  if (x != sptrs().end()) {
250  sptrs().erase (x);
251  if (debug_out) {
252  cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
253  }
254  }
255  }
256 
257  if (is_interesting_object (obj)) {
258 
259  pair<void const*, SPDebug*> newpair;
260 
261  newpair.first = sp;
262  newpair.second = new SPDebug (new Backtrace());
263 
264  sptrs().insert (newpair);
265 
266  if (debug_out) {
267  cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
268  << " UC = " << new_use_count
269  << " (total sp's = " << sptrs().size() << ')' << endl;
270  cerr << *newpair.second << endl;
271  }
272  }
273 }
274 
275 void
276 boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
277 {
279  PointerMap::iterator x = sptrs().find (sp);
280 
281  if (x != sptrs().end()) {
282  sptrs().erase (x);
283  if (debug_out) {
284  cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
285  }
286  }
287 }
288 
289 void
290 boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
291 {
292  if (is_interesting_object (obj)) {
294  pair<void const*, SPDebug*> newpair;
295 
296  newpair.first = sp;
297  newpair.second = new SPDebug (new Backtrace());
298 
299  sptrs().insert (newpair);
300  if (debug_out) {
301  cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
302  cerr << *newpair.second << endl;
303  }
304  }
305 }
306 
307 void
309 {
311  // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
312 }
313 
314 void
316 {
318 
319  if (sptrs().empty()) {
320  cerr << "There are no dangling shared ptrs\n";
321  } else {
322  for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
323  cerr << "Shared ptr @ " << x->first << " history: "
324  << *x->second
325  << endl;
326  }
327  }
328 }
329 
330 namespace boost {
331 
332 void sp_scalar_constructor_hook( void *, std::size_t, void *)
333 {
334 }
335 
336 void sp_scalar_destructor_hook( void *, std::size_t, void *)
337 {
338 }
339 
340 void sp_counter_ref_hook (void* /*pn*/, long /* use count */)
341 {
342 }
343 
344 void sp_counter_release_hook (void* /*pn*/, long /*use_count*/)
345 {
346 }
347 
349 {
350 }
351 
353 {
354 }
355 
357 {
358 }
359 
361 {
362 }
363 
364 }
static Glib::Threads::Mutex & the_lock()
Definition: boost_debug.cc:140
void boost_debug_shared_ptr_operator_equals(void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
Definition: boost_debug.cc:180
void sp_scalar_destructor_hook(void *)
Definition: boost_debug.cc:360
static IPointerMap * _interesting_pointers
Definition: boost_debug.cc:131
SPDebug(Backtrace *c)
Definition: boost_debug.cc:101
Definition: Beats.hpp:239
void sp_counter_ref_hook(void *, long)
Definition: boost_debug.cc:340
void sp_array_destructor_hook(void *)
Definition: boost_debug.cc:352
Backtrace * ref
Definition: boost_debug.cc:81
std::ostream & print(std::ostream &str) const
Definition: boost_debug.cc:59
static Glib::Threads::Mutex * _the_lock
Definition: boost_debug.cc:139
void boost_debug_shared_ptr_constructor(void const *sp, void const *obj, int use_count)
Definition: boost_debug.cc:290
void * trace[200]
Definition: boost_debug.cc:44
void boost_debug_count_ptrs()
Definition: boost_debug.cc:308
std::ostream & operator<<(std::ostream &str, const Backtrace &bt)
Definition: boost_debug.cc:48
void boost_debug_shared_ptr_show_live_debugging(bool yn)
Definition: boost_debug.cc:163
std::multimap< void const *, SPDebug * > PointerMap
Definition: boost_debug.cc:118
IPointerMap & interesting_pointers()
Definition: boost_debug.cc:132
PointerMap & sptrs()
Definition: boost_debug.cc:124
BTPair(Backtrace *bt)
Definition: boost_debug.cc:84
void boost_debug_shared_ptr_destructor(void const *sp, void const *obj, int use_count)
Definition: boost_debug.cc:276
Backtrace * rel
Definition: boost_debug.cc:82
void sp_counter_release_hook(void *, long)
Definition: boost_debug.cc:344
void sp_array_constructor_hook(void *)
Definition: boost_debug.cc:348
size_t size
Definition: boost_debug.cc:45
std::map< void const *, const char * > IPointerMap
Definition: boost_debug.cc:119
Backtrace * destructor
Definition: boost_debug.cc:99
void sp_scalar_constructor_hook(void *)
Definition: boost_debug.cc:356
static bool is_interesting_object(void const *ptr)
Definition: boost_debug.cc:149
void boost_debug_shared_ptr_reset(void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
Definition: boost_debug.cc:228
static bool debug_out
Definition: boost_debug.cc:160
void boost_debug_list_ptrs()
Definition: boost_debug.cc:315
Backtrace * constructor
Definition: boost_debug.cc:98
static PointerMap * _sptrs
Definition: boost_debug.cc:123
void boost_debug_shared_ptr_mark_interesting(void *ptr, const char *type)
Definition: boost_debug.cc:169