CxxDbg Features

Modern C++ programs make heavy use of standard library types, functional style code, and custom functional wrappers. Existing debuggers provide only partial support for these constructs. A step-into operation at a call through a functional object, such as a std::function or the result of std::bind, enters the standard library implementation instead of the target function. Value formatters typically cover common standard library containers and strings, but provide limited support for functional objects and do not expose the source location of the wrapped target. Stack traces contain a significant number of standard library frames, and function names are difficult to read when complex template parameters are involved. The main goal of the CxxDbg project is to solve these problems.

Advanced stepping functions

Step to the target of functional objects

A step-into operation at a call through standard functional objects, such as std::function or the result of std::bind, steps directly into the target function. Standard library code is skipped in both directions, so step-out returns to the call site rather than to library internals.

Stepping directly into the target of a functional object

Skip standard library functions

Standard library functions are skipped even when the call target is the library function itself. A step-into operation at v.begin() or v.end() does not stop in the library implementation and continues to the first function defined in user code.

Stepping over standard library functions

Customize step behavior

Stepping is not limited to the standard library. The regular expressions used to detect step targets are configurable, so third-party libraries and user-defined functional objects can be handled the same way. In the example, adding ^my_functor:: to the step settings steps through a user-defined my_functor object to its target.

Customizing which functions to step through

Value formatters

Values are formatted by dbgfmt, a value and type formatting framework with built-in formatters for libstdc++ and libc++. Alongside the formatted value, it extracts the source location of the value and its type. The framework does not depend on any debugger and can be reused in other tools.

Lambda expressions

The value of a lambda shows the name of the target lambda expression and its position in the source code, together with the captured variables. In the example, the value of lambda shows the captured z.

int z;
auto lambda = [z](int x, int y) -> auto {
    return x + y + z;
};

auto res = lambda(10, 20);
Displaying the value of a lambda expression

Standard functional objects

The value of a std::bind result shows the target function together with the bound arguments and placeholders. std::function and std::reference_wrapper values are formatted as well. In the example, a std::bind result is wrapped in a std::function object.

void foo(int x, int y) {
    ...
}

std::function<void(int)> bf = std::bind(&foo, _1, 10);
bf(20);
Displaying the value of a std::bind result

Standard library coverage

Built-in formatters cover the following standard library types, for both libstdc++ and libc++.

  • Containers
  • Strings
  • Smart pointers
  • Functional types
  • Utility types
  • chrono & regex

libstdc++

The GNU C++ Library

libc++

The LLVM/Clang C++ Library

Call stack grouping

Frames of no interest become child items

Frames of no interest are moved into child items, so user frames are not separated by library code. In the example, a call through std::function adds four standard library frames between main and foo. They are grouped under foo and can be expanded when low-level debugging is needed.

int foo(int x, int y) {
    ...
}

std::function<int (int, int)> foo_f = &foo;
foo_f(10, 20);
Call stack panel with standard library frames folded and expanded