mr-edd.co.uk :: horsing around with the C++ programming language

dbg

dbg is a library that I now use in all my home-grown projects, containing various different types of assert macros, each of which prints a traceback for the point of failure. It also includes tools for capturing tracebacks of exception throw-sites.

The low-level frame collection and symbol lookup code is also exposed in the public headers should anyone wish to use these facilities in their own assert macros rather than use dbg's directly.

Most notably, this is the first attempt I've made at implementing my own symbol lookup code for MinGW targets. My older stack_trace library uses libbfd and libiberty which are respectively licensed under the GPL and LGPL. dbg is released under the Boost Software License 1.0, meaning the symbol collection method can be freely used in 'closed-source' code.

OS X and Windows are supported. Adaptation to other UNIX systems shouldn't take much work.

Recent activity

Code

Clone the repository using mercurial:

> hg clone https://bitbucket.org/edd/dbg

Or get a zip file of the code.

Quick start

The DBG_ASSERT macro provides a traceback on failure and additional information can be added with the DBG_TAG macro:

DBG_ASSERT(x + y > z), DBG_TAG(x), DBG_TAG(y), DBG_TAG(z);

On failure:

[15:40:10.590283] An assertion has been triggered:

   location: assert_example.cpp:36
   function: void oops()
  condition: x + y > z
        'x': -4
        'y': 17
        'z': 491.72

    0x0000000100001653: oops() in build/gcc-debug-64/assert_example/bin/assert_example
    0x00000001000018c1: h() in build/gcc-debug-64/assert_example/bin/assert_example
    0x00000001000018cc: g() in build/gcc-debug-64/assert_example/bin/assert_example
    0x00000001000018d7: f() in build/gcc-debug-64/assert_example/bin/assert_example
    0x00000001000018ee: main in build/gcc-debug-64/assert_example/bin/assert_example
    0x0000000100001304: start in build/gcc-debug-64/assert_example/bin/assert_example

Other macros provided include:

'Hot' variants of the above macros are also available e.g. DBG_HOT_ASSERT(denominator != 0), DBG_HOT_TAG(denominator);. These are always no-ops unless explicitly enabled. Useful for situations where it is known that normal assertions render builds unusably slow for day-to-day development.

DBG_STATIC_ASSERT provides a static assertion macro that can be used at any scope in C++ source code.

Tracebacks

A traceback can be collected as follows:

#include <dbg/frames.hpp>
#include <dbg/symbols.hpp>
#include <iostream>

dbg::symdb db;
dbg::call_stack<64> traceback;
traceback.collect(0);
traceback.log(db, std::cout);

If DBG_THROW is used to throw exceptions, a traceback will be printed if the exception is not caught by the application:

#include <dbg/throw.hpp>

// ...

DBG_THROW(std::runtime_error("oops"));
[15:58:29.751330] An uncaught exception has caused process termination:

    location: throw_example.cpp:18
    function: void hurl()
  expression: std::runtime_error("oops")
     details: oops

    0x000000010000179e: hurl() in build/gcc-debug-64/throw_example/bin/throw_example
    0x00000001000017f3: h() in build/gcc-debug-64/throw_example/bin/throw_example
    0x00000001000017fe: g() in build/gcc-debug-64/throw_example/bin/throw_example
    0x0000000100001809: f() in build/gcc-debug-64/throw_example/bin/throw_example
    0x0000000100001814: main in build/gcc-debug-64/throw_example/bin/throw_example
    0x0000000100001740: start in build/gcc-debug-64/throw_example/bin/throw_example

terminate called throwing an exception

Another benefit of using DBG_THROW is that throw-site tracebacks can be obtained even if the exception is caught:

try
{
    something_that_throws();
}
catch (...)
{
    dbg::throw_info info = dbg::current_exception();
    if (!info.empty())
    {
        // thrown with DBG_THROW.
        dbg::call_stack<256> *traceback = info.trace;
        // ...
    }
}

Further reading

Additional information is available on the dbg wiki, including customization options and more in-depth usage instructions.

Comments

Steve

[10/12/2012 at 17:29:55]

No build instruction is there.

$python3 ./make.py
Traceback (most recent call last):
File "./make.py", line 6, in <module>
project('dbg')
NameError: name 'project' is not defined

How can I build it?

Edd

[12/12/2012 at 04:27:58]

Hi Steve. Please see the instructions on the wiki.

realazthat

[25/12/2012 at 23:17:13]

Hi, very nice. I was the one who once used wine's dbghelp together with stacktrace. Nice to see this lib!

Steven

[13/01/2013 at 00:40:27]

This looks useful, however, can't get it to build on windows.
Python 2.7

C:\edd-dbg-1abb9939664c\edd-dbg-1abb9939664c>python doozer.py make.py variant=msvc.cfg
-> unpacking doozerlib to c:\users\admin\appdata\local\temp\doozerlib-a80266ccf0f382bce4564fd51e4aa0
03143722ca.zip
-> using default of '5' for 'jobs' (the number of jobs that should be processed concurrently)
-> using default of 'C:\Program Files (x86)\Microsoft Visual Studio 10.0' for 'msvc.vsroot' (Visual
Studio installation directory)
-> using default of 'C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A' for 'msvc.sdkroot' (path t
o the Windows/Platform SDK)
-> using 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\vcvars32.bat' to augment build
environment
-> using default of '0x05010000' for 'win.ntddi_version' (the value of the NTDDI_VERSION macro, dete
rmining the minimum target OS)
-> loading subproject 'make.py'
-> using default of 'False' for 'dbg.optimize_out' (True if the library shouldn't be built e.g. for
release builds where asserts are dummy macros)
-> using default of 'None' for 'dbg.dbghelp_dll_path' (Location of a recent dbghelp.dll to be hardco
ded (optional))
-> loading subproject 'C:\edd-dbg-1abb9939664c\edd-fungo-9518b2e0588c\make.py'
-> ERROR! recursive subproject inclusion:
  C:\edd-dbg-1abb9939664c\edd-dbg-1abb9939664c\make.py > C:\edd-dbg-1abb9939664c\edd-fungo-9518b2e05
88c\make.py > C:\edd-dbg-1abb9939664c\edd-dbg-1abb9939664c\make.py

That said, does this only work with try/catch blocks?
Seems it would be much more useful if SetUnhandledExceptionFilter() is used?

Edd

[17/02/2013 at 00:40:18]

Hi Steven,

Sorry for not replying sooner. Does the circular inclusion mentioned in the final line indicate an actual problem?

The error seems to imply that the make.py for fungo is trying to load dbg as a subproject. Have you modified fungo's make.py? The canonical version doesn't depend on dbg.

If you're still having problems, please feel free to email me a zip of your setup, or file a bug on bitbucket.

Edd

[09/03/2013 at 09:56:06]

Just a note for anybody else having similar trouble to Steven, the build instructions on the wiki have been clarified to point out that test-o-matic is a required dependency when building with doozer.

Carlos

[06/04/2013 at 19:30:38]

Hi Mr Edd,

is there a way to show the stacktrace of an unhandled exception? (captured with SetUnhandledExceptionFilter).

I can only get something like this:

UnhandledExceptionFilter
RtlCreateUserThread
RtlInitializeExceptionChain

Thanks for your libs!

Edd

[21/05/2013 at 00:28:26]

Hi Carlos,

Sorry for the dreadfully late reply.

It would be possible with some further modifications to the library, but not as it stands.

If you still need this, please feel free to submit a feature request on the bug tracker. I can't make any promises as to when I'd get around to adding the feature, but it would certainly serve as a reminder.

(optional)
(optional)
(required, hint)

Links can be added like [this one -> http://www.mr-edd.co.uk], to my homepage.
Phrases and blocks of code can be enclosed in {{{triple braces}}}.
Any HTML markup will be escaped.