The full unambiguous names of C++ functions and variables include type names and namespace names, which makes them verbose. This is especially true with heavy use of templates because the type names include template parameter names (recursively). The challenge for a debugger (and other tools) is to display names that convey enough information to the user without overwhelming the UI. Pernosco tackles this by abbreviating names but making the abbreviations interactive.
Try it here! (Scroll down to GenericMethod
in the "stack of selected thread".)
When we demangle a C++ identifier, we demangle not to a string but to a tree. Template parameters are deeper in the tree than the template, and the name of a containing scope is deeper in the tree than the item it contains. For example, consider the full name of that GenericMethod
function:
mozilla::dom::BindingDetails::GenericMethod<NormalThisPolicy, ThrowExceptions>
This would be structured as:
(((mozilla)::dom)::BindingDetails)::GenericMethod<(NormalThisPolicy, ThrowExceptions)>
When we render the name, we replace some nodes of the tree with ellipses; clicking on an ellipsis expands that node to reveal its contents. Our default policy is to elide template parameters and to elide all but the innermost enclosing scope. This works really well.
C++ programs have a lot of compiler-generated functions that aren't present in source code, such as implicit destructors, assignment operators, etc. The Core Explorer blog post highlights that this is a serious problem for interactive debuggers designed for stepping through source code.
This is much less of a problem in Pernosco because it is not designed for stepping through source code! Our philosophy is that users should not step through code to build a picture of what happens over time; instead the debugger should visualize that picture for you directly. For example, Pernosco's callees view shows you all the function calls performed by some parent function invocation --- which works just as well whether that parent function was compiler-generated or in the source code. The callees view is also an excellent solution to the related problem that a single line of C++ code can call a huge number of functions implicitly (e.g. temporary construction/destruction and overloaded operators). In traditional debuggers you end up doing a lot of step-over calls until you finally step-into the call you care about (if you didn't accidentally step-over it, LOL RIP). With the callees view, you just scroll down to the call you care about and click on it. If you accidentally click on the wrong call, press the browser back button.
We do not, of course, have any magical solution to the problem that gcc and clang produce incomplete, underspecified, and often incompatible debug information. We have felt the same pain that is evident in the Core Explorer blog post! The underlying problem is that "gcc and gdb" and "LLVM and lldb" are mostly separate ecosystems, with the DWARF spec awkwardly trying to straddle the gap and alternative debuggers largely invisible. We do have some small advantages; in particular Pernosco does not need to decode call stacks.