|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +nav-class: dark |
| 4 | +categories: dmitry |
| 5 | +title: How to Get More Utility from the Debugger in CI |
| 6 | +author-id: dmitry |
| 7 | +author-name: Dmitry Arkhipov |
| 8 | +--- |
| 9 | + |
| 10 | +While some of my work in the third quarter of this year was dedicated to more |
| 11 | +work on Boost.JSON and Docca, the most interesting thing was definitely |
| 12 | +[pretty_printers](https://github.com/cppalliance/pretty_printers), a collection |
| 13 | +of utilities and build scripts which help dealing with debugger pretty printers |
| 14 | +and visualisers. Although currently it only supports |
| 15 | +[GDB](https://www.sourceware.org/gdb/), I'm planning to research |
| 16 | +[LLDB](https://lldb.llvm.org/) and |
| 17 | +[Natvis](https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022) |
| 18 | +integration too. |
| 19 | + |
| 20 | +The module naturally emerged from my work on GDB pretty printers for |
| 21 | +Boost.JSON. Even if you don't know what pretty printers are, you can probably |
| 22 | +guess just by their name: they are helpers that tell the debugger how to output |
| 23 | +objects of a particular type. These days standard libraries come with such |
| 24 | +helpers, and so when we try printing a container, we get useful information |
| 25 | +instead of unintelligible gibberish. If we provide similar helpers for our |
| 26 | +libraries we can significantly improve debugging experience for our users. |
| 27 | + |
| 28 | +But writing the helpers is only one half of the task. The other half is getting |
| 29 | +the debugger to actually load them. Let's look at the options GDB provides us |
| 30 | +for this. |
| 31 | + |
| 32 | +1. The user can manually load an extension that contains our helpers from the |
| 33 | + initialisation file. |
| 34 | +2. The debugger can automatically load the extension that matches the name of a |
| 35 | + binary that it loads (either a program or a shared library). |
| 36 | +3. The debugger can load the extension from a special section in the loaded |
| 37 | + binary itself. |
| 38 | + |
| 39 | +Option 1 is the most straightforward, and is also the least exciting. Option 2 |
| 40 | +is actually the one standard libraries go for. But there is a fundamental |
| 41 | +problem with it: it doesn't work for static libraries let alone header-only |
| 42 | +ones. A static library is never a binary loaded by the debugger, and the |
| 43 | +extension file name has to match the name of a loaded binary. Header-only |
| 44 | +libraries don't have a corresponding binary at all. The reason it works so well |
| 45 | +for standard libraries is that people very rarely link to them statically when |
| 46 | +they are actually working on their code, which is when they use a debugger. |
| 47 | + |
| 48 | +This leaves option 3: putting the extension into the binary. GDB documentation |
| 49 | +[explains how to do it](https://sourceware.org/gdb/current/onlinedocs/gdb.html/dotdebug_005fgdb_005fscripts-section.html). |
| 50 | +The catch is that the extension file needs to be preprocessed to effectively |
| 51 | +become an assembler command. This can be automated, though. In August Niall |
| 52 | +Douglas [posted on the Boost developers' mailing list](https://lists.boost.org/Archives/boost/2024/08/257480.php) |
| 53 | +about his and Braden Ganetsky's work on a script that does such preprocessing |
| 54 | +of a GDB extension file for his library. At that point I have experimented a |
| 55 | +little bit with such embedding and concluded that this is as good as it gets |
| 56 | +with pretty printers deployment. So, the first component of `pretty_printers` |
| 57 | +is a script that takes a GDB Python extension file and produces a C file |
| 58 | +suitable for embedding into a binary. |
| 59 | + |
| 60 | +But that's not all. In the same mailing list post Niall mentions that the |
| 61 | +reason Braden has collaborated with him was bugs he found in the embedding. |
| 62 | +This leads us to testing. Boost.JSON is quite rigorously tested. This has been |
| 63 | +made possible largely thanks to the C++ Alliance Drone instance. After I |
| 64 | +initially wrote GDB pretty printers for Boost.JSON I immediately started |
| 65 | +looking for a way to test them. The aforementioned mailing list post shows that |
| 66 | +my concern wasn't a purely theoretical one. |
| 67 | + |
| 68 | +After some research I discovered that with certain flags GDB can be run as a |
| 69 | +Python interpreter. Hence my original idea for testing pretty printers: a C++ |
| 70 | +program that sets up objects to print, and an accompanying Python script that |
| 71 | +tells GDB where to set breakpoints and what expressions to print, and compares |
| 72 | +the output with the expected strings. But I realised that keeping the two files |
| 73 | +in sync becomes rather unwieldy very quickly. That led to take 2: put the tests |
| 74 | +in the comments of the C++ test program, and generate a corresponding Python |
| 75 | +script from it. Not only it resulted in the tests immediately following the |
| 76 | +lines creating the objects used in those tests, it also allowed the support for |
| 77 | +putting tests in functions, loops, and spreading them across multiple files. |
| 78 | +The utility that generates such Python script is the second component of |
| 79 | +`pretty_printers`. |
| 80 | + |
| 81 | +This concludes the story of the two utilities contained in `pretty_printers`. |
| 82 | +The other important component of this module is the support for CMake and B2 |
| 83 | +build systems. The support doesn't simply include some boilerplate. The testing |
| 84 | +function also tells GDB to whitelist the directory where the tested binary is |
| 85 | +located, so that the extensions are loaded. Otherwise the user would have to do |
| 86 | +it manually, which is particularly annoying in CI. |
| 87 | + |
| 88 | +After I finished the work on the module, I decided that other libraries could |
| 89 | +benefit from it. It was suggested to me that I should submit the module for |
| 90 | +review to the Boost community. Previously there hasn't been any Boost tool |
| 91 | +reviews, but the Boost community was positive to the idea. I find this to be |
| 92 | +a very exciting development. |
| 93 | + |
| 94 | +Another exciting idea I had is to research other potential debugger helpers, |
| 95 | +unrelated to pretty printing and visualisation. For example, GDB allows |
| 96 | +extensions to register custom commands. There's also the possibility of |
| 97 | +orchestrating GDB to analyse a specific situation. E.g. put a breakpoint on |
| 98 | +this line, but only after another line was hit. While locally this is easily |
| 99 | +done manually, such functionality can be useful when the error only manifests |
| 100 | +on a platform you only have access to in CI. Such ideas hint that |
| 101 | +`pretty_printers` is a misnomer, and the module should be called something |
| 102 | +different. Maybe `debugger_utils`? |
0 commit comments