This RFC proposes a new frame-format setting that will color-highlight parts of a function name in the backtrace (or frame/thread info status). The motivation (similar to [RFC][ItaniumDemangler] New option to print compact C++ names, but is not mutually exclusive to that RFC), is to provide users with a more user-friendly backtrace when debugging heavily templated C++. Usually when looking at a backtrace, one wants to see the path of function calls that lead us to the frame we’re stopped in. Currently this information is not easy to obtain from a quick glance at a backtrace, especially when the demangled names include long scopes and template arguments (or other C++ constructs like function pointers, decltype
etc.). This proposal addresses these issues by providing a visual cue to quickly determine all function names involved in a backtrace.
I’m looking to discuss how much appetite the community has for this feature, and any thoughts/concerns on how the proposal integrates it into LLDB’s existing frame-format language.
Example
This is what the current LLDB backtrace looks like:
Changing the default ${function.name-with-args}
frame-format variable to the proposed ${function.name-with-args:%highlight_basename(ansi.fg.cyan)}
(the final syntax of this will probably differ) would yield:
Note how the basename of each frame is highlighted with the color specified in the setting.
Implementation Overview
The function names in backtraces are currently the ones we get from the LLVM demangler (more on that in the Alternatives Considered
section). So the high-level idea is to make the demangler track where in the demangled name the basename begins and ends. LLDB then takes this information, and when printing the frame name, it makes sure to highlight that portion of the demangled name.
A draft implementation can be found here: [WIP: DO NOT MERGE] [lldb][Format] Add option to highlight function names in backtraces by Michael137 · Pull Request #131836 · llvm/llvm-project · GitHub
Implementation Details
There are three parts to the implementation:
- Add infrastructure to LLVM’s
ItaniumDemangler
to track where certain portions of a C++ function name are in the demangled name. - Expose the new demangler information to LLDB
- Invent a mechanism to specify how to highlight a frame name in LLDB’s
frame-format
setting.
1. Demangler Changes
The idea that a function name can be decomposed into <scope, base, arguments>. The assumption is that given the ranges of those three elements and the demangled name, it is possible to reconstruct the full demangled name. The tracking of those ranges is pretty simple inside the demangler. We don’t ever deal with nesting, so whenever we recurse into a template argument list or another function type, we just stop tracking any positions. Once we recursed out of those, and are back to printing the top-level function name, we continue tracking the positions.
The draft implementation introduces a new structure to the llvm::itanium_demangle::OutputBuffer
, which is unfortunately the only way to keep state while printing the demangle tree (it already contains other kinds of information similar to this tracking. In [RFC][ItaniumDemangler] New option to print compact C++ names we propose to refactor this, but shouldn’t be a blocker unless people feel otherwise).
2. Integrating into LLDB
The ItaniumPartialDemangler
(which th lldb_private::Mangled
object uses) already has access to the OutputBuffer
. So LLDB can just fish the basename locations out of that and expose it from lldb_private::Function
, which we use in FormatEntity
to get the demangled name to print for each frame.
3. Frame Formatting Language Changes
We need to somehow let the user decide to highlight function names. We probably also want to let a user decide which color to use. So the prototype opted for re-using the (undocumented?) printf
format specifier infrastructure of the frame-format variable language. That allows us to add additional information to the ${function.name-with-args}
variable. We can invent new syntax like ${function.name-with-args:%<some new syntax>}
. There is already precendent for this for the %tid
format specifier. The prototype opted for:
${function.name-with-args:%highlight_basename(ansi.fg.cyan)}
Meaning we want to highlight the basename of ${function.name-with-args}
with ${ansi.fg.cyan}
.
Once we determine that a user wants to highlight the basename we pass that info to the CPlusPlusLanguage
plugin, which will print the individual portions of the demangled name using the positions it got from the demangler. We already do this kind of printing using the CPlusPlusNameParser
. The only difference is that there we determine the positions ourselves instead of asking the demangler.
Handling Other Languages
In the proposed implementation the highlighting is done entirely in the language plugin (and the demangler it chooses to use). The only common interface point is the new FormatEntity::Entry::HighlightSetting
which specifies the “kind” of highlighting to perform (currently only Kind::Basename
is implemented, but is easily extended to other parts of a function name if a language plugin wants that).
Alternatives Considered
- Don’t use demangled names for frame names; use the Clang’s type-printer instead
In [RFC][ItaniumDemangler] New option to print compact C++ names we discussed using names from debug-info and letting Clang pretty-print the names. This is currently not possible without changing the way LLDB reconstructs the Clang AST from DWARF. Particularly, template functions/classes AST nodes aren’t constructed in a way that would allow the clang::TypePrinter
to print template parameters (currently it would just drop the templates). I’m not sure how much work it would be to address this, though last time I investigated this, the consensus was that we would have to at the very least start representing generic template definitions in DWARF. Also note, this would only help for cases where debug-info is available.
- Using
CPlusPlusNameParser
to determine the positions of the basename/template parameters/etc., instead of doing this in the demangler.
This seems like a non-starter, since parsing C++ names is difficult and we don’t want to add additional reliance on CPlusPlusNameParser
.
CCing people who I’ve talked to about backtraces in the past
(@adrian.prantl @kastiglione @labath @dblaikie @jingham)