diff options
| -rw-r--r-- | ChangeLog | 45 | ||||
| -rw-r--r-- | INSTALL | 27 | ||||
| -rw-r--r-- | Makeconfig | 76 | ||||
| -rw-r--r-- | Makerules | 46 | ||||
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | README.pretty-printers | 169 | ||||
| -rw-r--r-- | Rules | 44 | ||||
| -rw-r--r-- | manual/install.texi | 30 | ||||
| -rw-r--r-- | nptl/Makefile | 18 | ||||
| -rw-r--r-- | nptl/nptl-printers.py | 633 | ||||
| -rw-r--r-- | nptl/nptl_lock_constants.pysym | 75 | ||||
| -rw-r--r-- | nptl/test-cond-printers.c | 57 | ||||
| -rw-r--r-- | nptl/test-cond-printers.py | 50 | ||||
| -rw-r--r-- | nptl/test-condattr-printers.c | 94 | ||||
| -rw-r--r-- | nptl/test-condattr-printers.py | 71 | ||||
| -rw-r--r-- | nptl/test-mutex-printers.c | 151 | ||||
| -rw-r--r-- | nptl/test-mutex-printers.py | 97 | ||||
| -rw-r--r-- | nptl/test-mutexattr-printers.c | 144 | ||||
| -rw-r--r-- | nptl/test-mutexattr-printers.py | 101 | ||||
| -rw-r--r-- | nptl/test-rwlock-printers.c | 78 | ||||
| -rw-r--r-- | nptl/test-rwlock-printers.py | 64 | ||||
| -rw-r--r-- | nptl/test-rwlockattr-printers.c | 98 | ||||
| -rw-r--r-- | nptl/test-rwlockattr-printers.py | 73 | ||||
| -rw-r--r-- | scripts/gen-py-const.awk | 118 | ||||
| -rw-r--r-- | scripts/test_printers_common.py | 364 | ||||
| -rw-r--r-- | scripts/test_printers_exceptions.py | 61 |
26 files changed, 2769 insertions, 20 deletions
@@ -1,3 +1,48 @@ +2016-12-08 Martin Galvan <martin.galvan@tallertechnologies.com> + + * INSTALL: Regenerated. + * Makeconfig: Add comments and whitespace to make the control flow + clearer. + (+link-printers-tests, +link-pie-printers-tests, + CFLAGS-printers-tests, installed-rtld-LDFLAGS, + built-rtld-LDFLAGS, link-libc-rpath, + link-libc-tests-after-rpath-link, + link-libc-printers-tests): New. + (rtld-LDFLAGS, rtld-tests-LDFLAGS, link-libc-tests-rpath-link, + link-libc-tests): Use the new variables as required. + * Makerules ($(py-const)): New rule. + generated: Add $(py-const). + * README.pretty-printers: New file. + * Rules (tests-printers-programs, tests-printers-out, py-env): New. + (others): Depend on $(py-const). + (tests): Depend on $(tests-printers-programs) or + $(tests-printers-out), + as required. Pass $(tests-printers) to merge-test-results.sh. + * manual/install.texi: Add requirements for testing the pretty + printers. + * nptl/Makefile (gen-py-const-headers, pretty-printers, + tests-printers, CFLAGS-test-mutexattr-printers.c + CFLAGS-test-mutex-printers.c, CFLAGS-test-condattr-printers.c, + CFLAGS-test-cond-printers.c, CFLAGS-test-rwlockattr-printers.c + CFLAGS-test-rwlock-printers.c, tests-printers-libs): Define. + * nptl/nptl-printers.py: New file. + * nptl/nptl_lock_constants.pysym: Likewise. + * nptl/test-cond-printers.c: Likewise. + * nptl/test-cond-printers.py: Likewise. + * nptl/test-condattr-printers.c: Likewise. + * nptl/test-condattr-printers.py: Likewise. + * nptl/test-mutex-printers.c: Likewise. + * nptl/test-mutex-printers.py: Likewise. + * nptl/test-mutexattr-printers.c: Likewise. + * nptl/test-mutexattr-printers.py: Likewise. + * nptl/test-rwlock-printers.c: Likewise. + * nptl/test-rwlock-printers.py: Likewise. + * nptl/test-rwlockattr-printers.c: Likewise. + * nptl/test-rwlockattr-printers.py: Likewise. + * scripts/gen-py-const.awk: Likewise. + * scripts/test_printers_common.py: Likewise. + * scripts/test_printers_exceptions.py: Likewise. + 2016-12-07 Joseph Myers <joseph@codesourcery.com> * scripts/build-many-glibcs.py (Context.__init__): Take strip @@ -224,6 +224,33 @@ You can specify 'stop-on-test-failure=y' when running 'make check' to make the test run stop and exit with an error status immediately when a failure occurs. + The GNU C Library pretty printers come with their own set of scripts +for testing, which run together with the rest of the testsuite through +'make check'. These scripts require the following tools to run +successfully: + + * Python 2.7.6/3.4.3 or later + + Python is required for running the printers' test scripts. + + * PExpect 4.0 + + The printer tests drive GDB through test programs and compare its + output to the printers'. PExpect is used to capture the output of + GDB, and should be compatible with the Python version in your + system. + + * GDB 7.8 or later with support for Python 2.7.6/3.4.3 or later + + GDB itself needs to be configured with Python support in order to + use the pretty printers. Notice that your system having Python + available doesn't imply that GDB supports it, nor that your + system's Python and GDB's have the same version. + +If these tools are absent, the printer tests will report themselves as +'UNSUPPORTED'. Notice that some of the printer tests require the GNU C +Library to be compiled with debugging symbols. + To format the 'GNU C Library Reference Manual' for printing, type 'make dvi'. You need a working TeX installation to do this. The distribution builds the on-line formatted version of the manual, as Info diff --git a/Makeconfig b/Makeconfig index a7858607b0..e9d8da9d60 100644 --- a/Makeconfig +++ b/Makeconfig @@ -416,6 +416,11 @@ $(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ $(+link-pie-after-libc) $(call after-link,$@) endef +define +link-pie-printers-tests +$(+link-pie-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \ + $(+link-pie-after-libc) +$(call after-link,$@) +endef endif # Command for statically linking programs with the C library. ifndef +link-static @@ -445,7 +450,8 @@ ifeq (yes,$(build-pie-default)) no-pie-ldflag = -no-pie +link = $(+link-pie) +link-tests = $(+link-pie-tests) -else ++link-printers-tests = $(+link-pie-printers-tests) +else # not build-pie-default +link-before-libc = $(CC) -nostdlib -nostartfiles -o $@ \ $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \ @@ -466,51 +472,87 @@ $(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ $(+link-after-libc) $(call after-link,$@) endef -endif -else +define +link-printers-tests +$(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \ + $(+link-after-libc) +$(call after-link,$@) +endef +endif # build-pie-default +else # build-static +link = $(+link-static) +link-tests = $(+link-static-tests) -endif -endif ++link-printers-tests = $(+link-static-tests) +endif # build-shared +endif # +link + +# The pretty printer test programs need to be compiled without optimizations +# so they won't confuse gdb. We could use either the 'GCC optimize' pragma +# or the 'optimize' function attribute to achieve this; however, at least on +# ARM, gcc always produces different debugging symbols when invoked with +# a -O greater than 0 than when invoked with -O0, regardless of anything else +# we're using to suppress optimizations. Therefore, we need to explicitly pass +# -O0 to it through CFLAGS. +# Additionally, the build system will try to -include $(common-objpfx)/config.h +# when compiling the tests, which will throw an error if some special macros +# (such as __OPTIMIZE__ and IS_IN_build) aren't defined. To avoid this, we +# tell gcc to define IS_IN_build. +CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build + ifeq (yes,$(build-shared)) +# These indicate whether to link using the built ld.so or the installed one. +installed-rtld-LDFLAGS = -Wl,-dynamic-linker=$(rtlddir)/$(rtld-installed-name) +built-rtld-LDFLAGS = -Wl,-dynamic-linker=$(elf-objpfx)ld.so + ifndef rtld-LDFLAGS -rtld-LDFLAGS = -Wl,-dynamic-linker=$(rtlddir)/$(rtld-installed-name) +rtld-LDFLAGS = $(installed-rtld-LDFLAGS) endif + ifndef rtld-tests-LDFLAGS ifeq (yes,$(build-hardcoded-path-in-tests)) -rtld-tests-LDFLAGS = -Wl,-dynamic-linker=$(elf-objpfx)ld.so +rtld-tests-LDFLAGS = $(built-rtld-LDFLAGS) else -rtld-tests-LDFLAGS = $(rtld-LDFLAGS) -endif -endif -endif +rtld-tests-LDFLAGS = $(installed-rtld-LDFLAGS) +endif # build-hardcoded-path-in-tests +endif # rtld-tests-LDFLAGS + +endif # build-shared + ifndef link-libc ifeq (yes,$(build-shared)) # We need the versioned name of libc.so in the deps of $(others) et al # so that the symlink to libc.so is created before anything tries to # run the linked programs. +link-libc-rpath = -Wl,-rpath=$(rpath-link) link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link) + ifeq (yes,$(build-hardcoded-path-in-tests)) -link-libc-tests-rpath-link = -Wl,-rpath=$(rpath-link) +link-libc-tests-rpath-link = $(link-libc-rpath) else link-libc-tests-rpath-link = $(link-libc-rpath-link) -endif +endif # build-hardcoded-path-in-tests + link-libc-before-gnulib = $(common-objpfx)libc.so$(libc.so-version) \ $(common-objpfx)$(patsubst %,$(libtype.oS),c) \ $(as-needed) $(elf-objpfx)ld.so \ $(no-as-needed) link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) + +link-libc-tests-after-rpath-link = $(link-libc-before-gnulib) $(gnulib-tests) link-libc-tests = $(link-libc-tests-rpath-link) \ - $(link-libc-before-gnulib) $(gnulib-tests) + $(link-libc-tests-after-rpath-link) +# Pretty printer test programs always require rpath instead of rpath-link. +link-libc-printers-tests = $(link-libc-rpath) \ + $(link-libc-tests-after-rpath-link) + # This is how to find at build-time things that will be installed there. rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) -else +else # build-static link-libc = $(common-objpfx)libc.a $(otherlibs) $(gnulib) $(common-objpfx)libc.a $(gnulib) link-libc-tests = $(common-objpfx)libc.a $(otherlibs) $(gnulib-tests) $(common-objpfx)libc.a $(gnulib-tests) -endif -endif +endif # build-shared +endif # link-libc # Differences in the linkers on the various platforms. LDFLAGS-rpath-ORIGIN = -Wl,-rpath,'$$ORIGIN' @@ -210,6 +210,52 @@ sed-remove-dotdot := -e 's@ *\([^ \/$$][^ \]*\)@ $$(..)\1@g' \ -e 's@^\([^ \/$$][^ \]*\)@$$(..)\1@g' endif +ifdef gen-py-const-headers +# We'll use a static pattern rule to match .pysym files with their +# corresponding generated .py files. +# The generated .py files go in the submodule's dir in the glibc build dir. +py-const-files := $(patsubst %.pysym,%.py,$(gen-py-const-headers)) +py-const-dir := $(objpfx) +py-const := $(addprefix $(py-const-dir),$(py-const-files)) +py-const-script := $(..)scripts/gen-py-const.awk + +# This is a hack we use to generate .py files with constants for Python +# pretty printers. It works the same way as gen-as-const. +# See scripts/gen-py-const.awk for details on how the awk | gcc mechanism +# works. +# +# $@.tmp and $@.tmp2 are temporary files we use to store the partial contents +# of the target file. We do this instead of just writing on $@ because, if the +# build process terminates prematurely, re-running Make wouldn't run this rule +# since Make would see that the target file already exists (despite it being +# incomplete). +# +# The sed line replaces "@name@SOME_NAME@value@SOME_VALUE@" strings from the +# output of 'gcc -S' with "SOME_NAME = SOME_VALUE" strings. +# The '-n' option, combined with the '/p' command, makes sed output only the +# modified lines instead of the whole input file. The output is redirected +# to a .py file; we'll import it in the pretty printers file to read +# the constants generated by gen-py-const.awk. +# The regex has two capturing groups, for SOME_NAME and SOME_VALUE +# respectively. Notice SOME_VALUE may be prepended by a special character, +# depending on the assembly syntax (e.g. immediates are prefixed by a '$' +# in AT&T x86, and by a '#' in ARM). We discard it using a complemented set +# before the second capturing group. +$(py-const): $(py-const-dir)%.py: %.pysym $(py-const-script) \ + $(common-before-compile) + $(make-target-directory) + $(AWK) -f $(py-const-script) $< \ + | $(CC) -S -o $@.tmp $(CFLAGS) $(CPPFLAGS) -x c - + echo '# GENERATED FILE\n' > $@.tmp2 + echo '# Constant definitions for pretty printers.' >> $@.tmp2 + echo '# See gen-py-const.awk for details.\n' >> $@.tmp2 + sed -n -r 's/^.*@name@([^@]+)@value@[^[:xdigit:]Xx-]*([[:xdigit:]Xx-]+)@.*/\1 = \2/p' \ + $@.tmp >> $@.tmp2 + mv -f $@.tmp2 $@ + rm -f $@.tmp + +generated += $(py-const) +endif # gen-py-const-headers ifdef gen-as-const-headers # Generating headers for assembly constants. @@ -141,6 +141,11 @@ Version 2.25 variable for a particular architecture in the GCC source file 'gcc/config.gcc'. +* GDB pretty printers have been added for mutex and condition variable + structures in POSIX Threads. When installed and loaded in gdb these pretty + printers show various pthread variables in human-readable form when read + using the 'print' or 'display' commands in gdb. + Security related changes: On ARM EABI (32-bit), generating a backtrace for execution contexts which diff --git a/README.pretty-printers b/README.pretty-printers new file mode 100644 index 0000000000..86629001e6 --- /dev/null +++ b/README.pretty-printers @@ -0,0 +1,169 @@ +README for the glibc Python pretty printers +=========================================== + +Pretty printers are gdb extensions that allow it to print useful, human-readable +information about a program's variables. For example, for a pthread_mutex_t +gdb would usually output something like this: + +(gdb) print mutex +$1 = { + __data = { + __lock = 22020096, + __count = 0, + __owner = 0, + __nusers = 0, + __kind = 576, + __spins = 0, + __elision = 0, + __list = { + __prev = 0x0, + __next = 0x0 + } + }, + __size = "\000\000P\001", '\000' <repeats 12 times>, "@\002", '\000' <repeats 21 times>, + __align = 22020096 +} + +However, with a pretty printer gdb will output something like this: + +(gdb) print mutex +$1 = pthread_mutex_t = { + Type = Normal, + Status = Unlocked, + Robust = No, + Shared = No, + Protocol = Priority protect, + Priority ceiling = 42 +} + +Before printing a value, gdb will first check if there's a pretty printer +registered for it. If there is, it'll use it, otherwise it'll print the value +as usual. Pretty printers can be registered in various ways; for our purposes +we register them for the current objfile by calling +gdb.printing.register_pretty_printer(). + +Currently our printers are based on gdb.RegexpCollectionPrettyPrinter, which +means they'll be triggered if the type of the variable we're printing matches +a given regular expression. For example, MutexPrinter will be triggered if +our variable's type matches the regexp '^pthread_mutex_t$'. + +Besides the printers themselves, each module may have a constants file which the +printers will import. These constants are generated from C headers during the +build process, and need to be in the Python search path when loading the +printers. + + +Installing and loading +---------------------- + +The pretty printers and their constant files may be installed in different paths +for each distro, though gdb should be able to automatically load them by itself. +When in doubt, you can use the 'info pretty-printer' gdb command to list the +loaded pretty printers. + +If the printers aren't automatically loaded for some reason, you should add the +following to your .gdbinit: + +python +import sys +sys.path.insert(0, '/path/to/constants/file/directory') +end + +source /path/to/printers.py + +If you're building glibc manually, '/path/to/constants/file/directory' should be +'/path/to/glibc-build/submodule', where 'submodule' is e.g. nptl. + + +Testing +------- + +The pretty printers come with a small test suite based on PExpect, which is a +Python module with Expect-like features for spawning and controlling interactive +programs. Each printer has a corresponding C program and a Python script +that uses PExpect to drive gdb through the program and compare its output to +the expected printer's. + +The tests run on the glibc host, which is assumed to have both gdb and PExpect; +if any of those is absent the tests will fail with code 77 (UNSUPPORTED). +Native builds can be tested simply by doing 'make check'; cross builds must use +cross-test-ssh.sh as test-wrapper, like this: + +make test-wrapper='/path/to/scripts/cross-test-ssh.sh user@host' check + +(Remember to share the build system's filesystem with the glibc host's through +NFS or something similar). + +Running 'make check' on a cross build will only compile the test programs, +without running the scripts. + + +Adding new pretty printers +-------------------------- + +Adding new pretty printers to glibc requires following these steps: + +1. Identify which constants must be generated from C headers, and write the +corresponding .pysym file. See scripts/gen-py-const.awk for more information +on how this works. The name of the .pysym file must be added to the +'gen-py-const-headers' variable in your submodule's Makefile (without the .pysym +extension). + +2. Write the pretty printer code itself. For this you can follow the gdb +Python API documentation, and use the existing printers as examples. The printer +code must import the generated constants file (which will have the same name +as your .pysym file). The names of the pretty printer files must be added +to the 'pretty-printers' variable in your submodule's Makefile (without the .py +extension). + +3. Write the unit tests for your pretty printers. The build system calls each +test script passing it the paths to the test program source, the test program +binary, and the printer files you added to 'pretty-printers' in the previous +step. The test scripts, in turn, must import scripts/test_printers_common +and call the init_test function passing it, among other things, the name of the +set of pretty printers to enable (as seen by running 'info pretty-printer'). +You can use the existing unit tests as examples. + +4. Add the names of the pretty printer tests to the 'tests-printers' variable +in your submodule's Makefile (without extensions). In addition, for each test +program you must define a corresponding CFLAGS-* variable and set it to +$(CFLAGS-printers-tests) to ensure they're compiled correctly. For example, +test-foo-printer.c requires the following: + +CFLAGS-test-foo-printer.c := $(CFLAGS-printers-tests) + +Finally, if your programs need to be linked with a specific library, you can add +its name to the 'tests-printers-libs' variable in your submodule's Makefile. + + +Known issues +------------ + +* Pretty printers are inherently coupled to the code they're targetting, thus +any changes to the target code must also update the corresponding printers. +On the plus side, the printer code itself may serve as a kind of documentation +for the target code. + +* Older versions of the gdb Python API have a bug where +gdb.RegexpCollectionPrettyPrinter would not be able to get a value's real type +if it was typedef'd. This would cause gdb to ignore the pretty printers for +types like pthread_mutex_t, which is defined as: + +typedef union +{ + ... +} pthread_mutex_t; + +This was fixed in commit 1b588015839caafc608a6944a78aea170f5fb2f6, and released +as part of gdb 7.8. However, typedef'ing an already typedef'd type may cause +a similar issue, e.g.: + +typedef pthread_mutex_t mutex; +mutex a_mutex; + +Here, trying to print a_mutex won't trigger the pthread_mutex_t printer. + +* The test programs must be compiled without optimizations. This is necessary +because the test scripts rely on the C code structure being preserved when +stepping through the programs. Things like aggressive instruction reordering +or optimizing variables out may make this kind of testing impossible. @@ -108,17 +108,28 @@ endif .PHONY: others tests bench bench-build +# Test programs for the pretty printers. +tests-printers-programs := $(addprefix $(objpfx),$(tests-printers)) + +# .out files with the output of running the pretty printer tests. +tests-printers-out := $(patsubst %,$(objpfx)%.out,$(tests-printers)) + ifeq ($(build-programs),yes) others: $(addprefix $(objpfx),$(others) $(sysdep-others) $(extra-objs)) else others: $(addprefix $(objpfx),$(extra-objs)) endif + +# Generate c |
