Blame manual/README.pretty-printers

Packit 6c4009
README for the glibc Python pretty printers
Packit 6c4009
===========================================
Packit 6c4009
Packit 6c4009
Pretty printers are gdb extensions that allow it to print useful, human-readable
Packit 6c4009
information about a program's variables.  For example, for a pthread_mutex_t
Packit 6c4009
gdb would usually output something like this:
Packit 6c4009
Packit 6c4009
(gdb) print mutex
Packit 6c4009
$1 = {
Packit 6c4009
  __data = {
Packit 6c4009
    __lock = 22020096,
Packit 6c4009
    __count = 0,
Packit 6c4009
    __owner = 0,
Packit 6c4009
    __nusers = 0,
Packit 6c4009
    __kind = 576,
Packit 6c4009
    __spins = 0,
Packit 6c4009
    __elision = 0,
Packit 6c4009
    __list = {
Packit 6c4009
      __prev = 0x0,
Packit 6c4009
      __next = 0x0
Packit 6c4009
    }
Packit 6c4009
  },
Packit 6c4009
  __size = "\000\000P\001", '\000' <repeats 12 times>, "@\002", '\000' <repeats 21 times>,
Packit 6c4009
  __align = 22020096
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
However, with a pretty printer gdb will output something like this:
Packit 6c4009
Packit 6c4009
(gdb) print mutex
Packit 6c4009
$1 = pthread_mutex_t = {
Packit 6c4009
  Type = Normal,
Packit 6c4009
  Status = Not acquired,
Packit 6c4009
  Robust = No,
Packit 6c4009
  Shared = No,
Packit 6c4009
  Protocol = Priority protect,
Packit 6c4009
  Priority ceiling = 42
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Before printing a value, gdb will first check if there's a pretty printer
Packit 6c4009
registered for it.  If there is, it'll use it, otherwise it'll print the value
Packit 6c4009
as usual.  Pretty printers can be registered in various ways; for our purposes
Packit 6c4009
we register them for the current objfile by calling
Packit 6c4009
gdb.printing.register_pretty_printer().
Packit 6c4009
Packit 6c4009
Currently our printers are based on gdb.RegexpCollectionPrettyPrinter, which
Packit 6c4009
means they'll be triggered if the type of the variable we're printing matches
Packit 6c4009
a given regular expression.  For example, MutexPrinter will be triggered if
Packit 6c4009
our variable's type matches the regexp '^pthread_mutex_t$'.
Packit 6c4009
Packit 6c4009
Besides the printers themselves, each module may have a constants file which the
Packit 6c4009
printers will import.  These constants are generated from C headers during the
Packit 6c4009
build process, and need to be in the Python search path when loading the
Packit 6c4009
printers.
Packit 6c4009
Packit 6c4009
Packit 6c4009
Installing and loading
Packit 6c4009
----------------------
Packit 6c4009
Packit 6c4009
The pretty printers and their constant files may be installed in different paths
Packit 6c4009
for each distro, though gdb should be able to automatically load them by itself.
Packit 6c4009
When in doubt, you can use the 'info pretty-printer' gdb command to list the
Packit 6c4009
loaded pretty printers.
Packit 6c4009
Packit 6c4009
If the printers aren't automatically loaded for some reason, you should add the
Packit 6c4009
following to your .gdbinit:
Packit 6c4009
Packit 6c4009
python
Packit 6c4009
import sys
Packit 6c4009
sys.path.insert(0, '/path/to/constants/file/directory')
Packit 6c4009
end
Packit 6c4009
Packit 6c4009
source /path/to/printers.py
Packit 6c4009
Packit 6c4009
If you're building glibc manually, '/path/to/constants/file/directory' should be
Packit 6c4009
'/path/to/glibc-build/submodule', where 'submodule' is e.g. nptl.
Packit 6c4009
Packit 6c4009
Packit 6c4009
Testing
Packit 6c4009
-------
Packit 6c4009
Packit 6c4009
The pretty printers come with a small test suite based on PExpect, which is a
Packit 6c4009
Python module with Expect-like features for spawning and controlling interactive
Packit 6c4009
programs.  Each printer has a corresponding C program and a Python script
Packit 6c4009
that uses PExpect to drive gdb through the program and compare its output to
Packit 6c4009
the expected printer's.
Packit 6c4009
Packit 6c4009
The tests run on the glibc host, which is assumed to have both gdb and PExpect;
Packit 6c4009
if any of those is absent the tests will fail with code 77 (UNSUPPORTED).
Packit 6c4009
Native builds can be tested simply by doing 'make check'; cross builds must use
Packit 6c4009
cross-test-ssh.sh as test-wrapper, like this:
Packit 6c4009
Packit 6c4009
make test-wrapper='/path/to/scripts/cross-test-ssh.sh user@host' check
Packit 6c4009
Packit 6c4009
(Remember to share the build system's filesystem with the glibc host's through
Packit 6c4009
NFS or something similar).
Packit 6c4009
Packit 6c4009
Running 'make check' on a cross build will only compile the test programs,
Packit 6c4009
without running the scripts.
Packit 6c4009
Packit 6c4009
Packit 6c4009
Adding new pretty printers
Packit 6c4009
--------------------------
Packit 6c4009
Packit 6c4009
Adding new pretty printers to glibc requires following these steps:
Packit 6c4009
Packit 6c4009
1. Identify which constants must be generated from C headers, and write the
Packit 6c4009
corresponding .pysym file.  See scripts/gen-py-const.awk for more information
Packit 6c4009
on how this works.  The name of the .pysym file must be added to the
Packit 6c4009
'gen-py-const-headers' variable in your submodule's Makefile (without the .pysym
Packit 6c4009
extension).
Packit 6c4009
Packit 6c4009
2. Write the pretty printer code itself.  For this you can follow the gdb
Packit 6c4009
Python API documentation, and use the existing printers as examples.  The printer
Packit 6c4009
code must import the generated constants file (which will have the same name
Packit 6c4009
as your .pysym file).  The names of the pretty printer files must be added
Packit 6c4009
to the 'pretty-printers' variable in your submodule's Makefile (without the .py
Packit 6c4009
extension).
Packit 6c4009
Packit 6c4009
3. Write the unit tests for your pretty printers.  The build system calls each
Packit 6c4009
test script passing it the paths to the test program source, the test program
Packit 6c4009
binary, and the printer files you added to 'pretty-printers' in the previous
Packit 6c4009
step.  The test scripts, in turn, must import scripts/test_printers_common
Packit 6c4009
and call the init_test function passing it, among other things, the name of the
Packit 6c4009
set of pretty printers to enable (as seen by running 'info pretty-printer').
Packit 6c4009
You can use the existing unit tests as examples.
Packit 6c4009
Packit 6c4009
4. Add the names of the pretty printer tests to the 'tests-printers' variable
Packit 6c4009
in your submodule's Makefile (without extensions).  In addition, for each test
Packit 6c4009
program you must define a corresponding CFLAGS-* and CPPFLAGS-* variable and
Packit 6c4009
set it to $(CFLAGS-printers-tests) to ensure they're compiled correctly.  For
Packit 6c4009
example, test-foo-printer.c requires the following:
Packit 6c4009
Packit 6c4009
CFLAGS-test-foo-printer.c := $(CFLAGS-printers-tests)
Packit 6c4009
CPPFLAGS-test-foo-printer.c := $(CFLAGS-printers-tests)
Packit 6c4009
Packit 6c4009
Finally, if your programs need to be linked with a specific library, you can add
Packit 6c4009
its name to the 'tests-printers-libs' variable in your submodule's Makefile.
Packit 6c4009
Packit 6c4009
Packit 6c4009
Known issues
Packit 6c4009
------------
Packit 6c4009
Packit 6c4009
* Pretty printers are inherently coupled to the code they're targetting, thus
Packit 6c4009
any changes to the target code must also update the corresponding printers.
Packit 6c4009
On the plus side, the printer code itself may serve as a kind of documentation
Packit 6c4009
for the target code.
Packit 6c4009
Packit 6c4009
* There's no guarantee that the information the pretty printers provide is
Packit 6c4009
complete, i.e. some details might be left off.  For example, the pthread_mutex_t
Packit 6c4009
printers won't report whether a thread is spin-waiting in an attempt to acquire
Packit 6c4009
the mutex.
Packit 6c4009
Packit 6c4009
* Older versions of the gdb Python API have a bug where
Packit 6c4009
gdb.RegexpCollectionPrettyPrinter would not be able to get a value's real type
Packit 6c4009
if it was typedef'd.  This would cause gdb to ignore the pretty printers for
Packit 6c4009
types like pthread_mutex_t, which is defined as:
Packit 6c4009
Packit 6c4009
typedef union
Packit 6c4009
{
Packit 6c4009
  ...
Packit 6c4009
} pthread_mutex_t;
Packit 6c4009
Packit 6c4009
This was fixed in commit 1b588015839caafc608a6944a78aea170f5fb2f6, and released
Packit 6c4009
as part of gdb 7.8.  However, typedef'ing an already typedef'd type may cause
Packit 6c4009
a similar issue, e.g.:
Packit 6c4009
Packit 6c4009
typedef pthread_mutex_t mutex;
Packit 6c4009
mutex a_mutex;
Packit 6c4009
Packit 6c4009
Here, trying to print a_mutex won't trigger the pthread_mutex_t printer.
Packit 6c4009
Packit 6c4009
* The test programs must be compiled without optimizations.  This is necessary
Packit 6c4009
because the test scripts rely on the C code structure being preserved when
Packit 6c4009
stepping through the programs.  Things like aggressive instruction reordering
Packit 6c4009
or optimizing variables out may make this kind of testing impossible.