libcwd

Features

End-users of an application don't need to install libcwd.
The use of namespaces prevents name collisions between debug channels of different libraries.
Debug channels and devices can be turned on or off on a per thread basis.
All debug code can be omitted from the executable by not defining a single CWDEBUG macro.
Code using libcwd looks clean and is surveyable as a result of using a few well-defined macros, avoiding the need of disturbing #ifdef CWDEBUG ... #endif constructs.
Debug output is written to an ostream and as such type-safe and customizable as is usual for C++ ostreams.
An arbitrary number of debug channels and debug devices can be created without any penalty in terms of cpu usage.
Full support for all forms of iterative and recursive calls.
Debug output is surveyable as a result of several possibilities to format the output, like a margin string, a marker string, indentation and fixed-width channel labels.  All formatting is thread specific.
Printing the type of arbitrary variables in demangled form.
Printing addresses in source file:line number presentation.
Deallocation pointer validation.
Magic numbers around allocated memory blocks in order to detect buffer overruns.
Printing an overview of current memory allocations, including start address, size, type of allocated object, source file and line number of allocation and a user definable description.
Finding allocation information with only a pointer that points inside an allocated memory block, in logarithmic time.

"Screen shot"

code example
Dout(dc::notice|error_cf, "Hello World");
<- margin -> NOTICE <- marker -> <- indentation ->  Hello World : error string <new-line>
output example
NOTICE  : Entering exec_prog()
SYSTEM  : pipe([3, 4]) = 0
SYSTEM  : pipe([5, 6]) = 0
  child MALLOC  : operator new (size = 24) = <unfinished>
  child BFD     :     Loading debug symbols from /home/carlo/c++/bfd/bfd...  done
SYSTEM  : fork() = 13078 [parent process]
SYSTEM  : close(4) = 0
SYSTEM  : close(6) = 0
  child BFD     :     Loading debug symbols from /home/carlo/c++/libcw/lib/libcwd.so.0 (40013000) ... done
  child BFD     :     Loading debug symbols from /usr/lib/libstdc++-libc6.1-2.so.3 (40057000) ... done
  child BFD     :     Loading debug symbols from /lib/libm.so.6 (4009e000) ... done
  child BFD     :     Loading debug symbols from /lib/libc.so.6 (400ba000) ... done
  child BFD     :     Loading debug symbols from /usr/lib/libbfd-2.9.5.0.14.so (401ad000) ... done
  child BFD     :     Loading debug symbols from /lib/ld-linux.so.2 (40000000) ... done
  child BFD     :     0x40082003 is at (streambuf.cc:211)
  child MALLOC  : <continued> 0x8053a68
SYSTEM  : poll( [ { 3, POLLIN, 0 }, { 5, POLLIN, 0 }, { 7, POLLIN, POLLIN } ], 3, -1) = 1
  child SYSTEM  : fork() = 0 [child process]
  child SYSTEM  : close(3) = 0
  child SYSTEM  : close(5) = 0
  child SYSTEM  : close(1) = 0
  child SYSTEM  : close(2) = 0
  child SYSTEM  : dup2(4, 1) = 1
  child SYSTEM  : dup2(6, 2) = 2
  child SYSTEM  : close(4) = 0
SYSTEM  : poll( [ { 3, POLLIN, POLLIN }, { 5, POLLIN, 0 }, { 7, POLLIN, 0 } ], 3, -1) = 1
SYSTEM  : read(3, "\t", 128) = 1
SYSTEM  : read(3, "libcwd.so.0", 128) = 11
SYSTEM  : read(3, " => ", 128) = 4
SYSTEM  : read(3, "/usr/lib/libcwd.so.0", 128) = 20
SYSTEM  : read(3, " (0x", 128) = 4
SYSTEM  : read(3, "40018000", 128) = 8
SYSTEM  : read(3, ")\n", 128) = 2
NOTICE  : child process stdout: "\tlibcwd.so.0 => /usr/lib/libcwd.so.0 (0x40018000)\n"
code example
template<typename T>
B<T>::~B(void)
{
  Dout(dc::notice, "Calling the destructor of " <<
                   libcwd::type_info_of(*this).demangled_name() << " (this == " << this << ")");
  libcwd::alloc_ct const* alloc = libcwd::find_alloc(this);
  if (sizeof(*this) != alloc->size())
  {
    Debug(dc::malloc.off());
    Debug(libcw_do.push_marker());
    Debug(libcw_do.marker().assign(": | "));
    Dout(dc::notice, "This is a base class of an object starting at " << alloc->start());
    Dout(dc::notice, "The type of the pointer to the allocated object is " <<
                     alloc->type_info().demangled_name());
    Debug(libcw_do.marker().assign(": ` "));
    Dout(dc::notice, "The destructor was called from " << location_ct(builtin_return_address(0)));
    Debug(dc::malloc.on());
    Debug(libcw_do.pop_marker());
  }
}

(Click here to download/view the complete program.)

output
MALLOC  : operator new (size = 4) = 0x80584d0 [screenshot.cc:56]
NOTICE  : b is 0x80584d0
MALLOC  : operator new (size = 12) = 0x8100fa0 [screenshot.cc:60]
NOTICE  : c is 0x8100fa0
NOTICE  : Calling the destructor of B<int> (this == 0x80584d0)
MALLOC  : delete 0x80584d0        screenshot.cc:56   B<int>; (sz = 4)  object `b'
NOTICE  : Calling the destructor of B<B<char> > (this == 0x8100fa4)
NOTICE  : | This is a base class of an object starting at 0x8100fa0
NOTICE  : | The type of the pointer to the allocated object is C<double, B<char> >*
NOTICE  : ` The destructor was called from screenshot.cc:65
MALLOC  : delete 0x8100fa0        screenshot.cc:60   C<double, B<char> >; (sz = 12)  object `c'
Another output example
MALLOC  : malloc(10) = <unfinished>
WARNING :     Object file /lib/ld-linux.so.2 does not have debug info.  Address lookups inside this object file will result in a function name only, not a source file location.
MALLOC  : <continued> 0x8125978 [ld-linux.so.2:open_path]
MALLOC  : calloc(586, 1) = 0x8124f10 [ld-linux.so.2:_dl_new_object]
MALLOC  : realloc(0x0, 138) = 0x8125170 [ld-linux.so.2:_dl_new_object]
MALLOC  : malloc(52) = 0x8110fa0 [ld-linux.so.2:_dl_map_object_deps]
MALLOC  : calloc(8, 16) = 0x8052c98 [ld-linux.so.2:_dl_check_map_versions]
MALLOC  : malloc(68) = <unfinished>
WARNING :     Object file /lib/tls/libc.so.6 does not have debug info.  Address lookups inside this object file will result in a function name only, not a source file location.
MALLOC  : <continued> 0x80569e0 [libc.so.6:dl_open_worker]
BFD     : Loading debug symbols from module.so (0x40424000) ... done (179 symbols)
MALLOC  : malloc(310) = <unfinished>
BFD     :     Loading debug info from module.so... done
BFD     :     address 0x4042bc90 corresponds to module.cc:24
MALLOC  : <continued> 0x81ab7b0 [module.cc:24]
MALLOC  : malloc(300) = <unfinished>
BFD     :     address 0x4042ba86 corresponds to module.cc:13
MALLOC  : <continued> 0x81ab8f8 [module.cc:13]
MALLOC  : Allocated memory: 1592 bytes in 8 blocks.
malloc    0x81ab8f8            module.cc:13   void*; (sz = 300)  Allocated inside static_test_symbol
malloc    0x81ab7b0            module.cc:24   void*; (sz = 310)  Allocated inside global_test_symbol
malloc    0x80569e0 dl_open_worker            <unknown type>; (sz = 68)
malloc    0x8052c98 _dl_check_map_versions    <unknown type>; (sz = 128)
malloc    0x8110fa0 _dl_map_object_deps       <unknown type>; (sz = 52)
realloc   0x8125170 _dl_new_object            <unknown type>; (sz = 138)
malloc    0x8124f10 _dl_new_object            <unknown type>; (sz = 586)
malloc    0x8125978 open_path                 <unknown type>; (sz = 10)
MALLOC  : free(0x81ab7b0)            module.cc:24   void*; (sz = 310)  Allocated inside global_test_symbol
MALLOC  : free(0x81ab8f8)            module.cc:13   void*; (sz = 300)  Allocated inside static_test_symbol
MALLOC  : free(0x8052c98) _dl_check_map_versions    <unknown type>; (sz = 128)
MALLOC  : free(0x8125170) _dl_new_object            <unknown type>; (sz = 138)
MALLOC  : free(0x8125978) open_path                 <unknown type>; (sz = 10)
MALLOC  : Trying to free NULL - ignored.
MALLOC  : Trying to free NULL - ignored.
MALLOC  : free(0x8124f10) _dl_new_object            <unknown type>; (sz = 586)
MALLOC  : free(0x8110fa0) _dl_map_object_deps       <unknown type>; (sz = 52)
NOTICE  : Finished