summaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch')
-rw-r--r--meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch3197
1 files changed, 3197 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch b/meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch
new file mode 100644
index 0000000000..9eb635d716
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0003-Add-pretty-printers-for-the-NPTL-lock-types.patch
@@ -0,0 +1,3197 @@
1From 246fee86fc90c57738ee282a061039f82832f4ea Mon Sep 17 00:00:00 2001
2From: Catalin Enache <catalin.enache@windriver.com>
3Date: Fri, 30 Jun 2017 13:42:04 +0300
4Subject: [PATCH 3/6] Add pretty printers for the NPTL lock types
5
6This patch adds pretty printers for the following NPTL types:
7
8- pthread_mutex_t
9- pthread_mutexattr_t
10- pthread_cond_t
11- pthread_condattr_t
12- pthread_rwlock_t
13- pthread_rwlockattr_t
14
15To load the pretty printers into your gdb session, do the following:
16
17python
18import sys
19sys.path.insert(0, '/path/to/glibc/build/nptl/pretty-printers')
20end
21
22source /path/to/glibc/source/pretty-printers/nptl-printers.py
23
24You can check which printers are registered and enabled by issuing the
25'info pretty-printer' gdb command. Printers should trigger automatically when
26trying to print a variable of one of the types mentioned above.
27
28The printers are architecture-independent, and were tested on an AMD64 running
29Ubuntu 14.04 and an x86 VM running Fedora 24.
30
31In order to work, the printers need to know the values of various flags that
32are scattered throughout pthread.h and pthreadP.h as enums and #defines. Since
33replicating these constants in the printers file itself would create a
34maintenance burden, I wrote a script called gen-py-const.awk that Makerules uses
35to extract the constants. This script is pretty much the same as gen-as-const.awk,
36except it doesn't cast the constant values to 'long' and is thorougly documented.
37The constants need only to be enumerated in a .pysym file, which is then referenced
38by a Make variable called gen-py-const-headers.
39
40As for the install directory, I discussed this with Mike Frysinger and Siddhesh
41Poyarekar, and we agreed that it can be handled in a separate patch, and shouldn't
42block merging of this one.
43
44In addition, I've written a series of test cases for the pretty printers.
45Each lock type (mutex, condvar and rwlock) has two test programs, one for itself
46and other for its related 'attributes' object. Each test program in turn has a
47PExpect-based Python script that drives gdb and compares its output to the
48expected printer's. The tests run on the glibc host, which is assumed to have
49both gdb and PExpect; if either is absent the tests will fail with code 77
50(UNSUPPORTED). For cross-testing you should use cross-test-ssh.sh as test-wrapper.
51I've tested the printers on both native builds and a cross build using a Beaglebone
52Black running Debian, with the build system's filesystem shared with the board
53through NFS.
54
55Finally, I've written a README that explains all this and more.
56
57 * INSTALL: Regenerated.
58 * Makeconfig: Add comments and whitespace to make the control flow
59 clearer.
60 (+link-printers-tests, +link-pie-printers-tests, CFLAGS-printers-tests,
61 installed-rtld-LDFLAGS, built-rtld-LDFLAGS, link-libc-rpath,
62 link-libc-tests-after-rpath-link, link-libc-printers-tests): New.
63 (rtld-LDFLAGS, rtld-tests-LDFLAGS, link-libc-tests-rpath-link,
64 link-libc-tests): Use the new variables as required.
65 * Makerules ($(py-const)): New rule.
66 generated: Add $(py-const).
67 * README.pretty-printers: New file.
68 * Rules (tests-printers-programs, tests-printers-out, py-env): New.
69 (others): Depend on $(py-const).
70 (tests): Depend on $(tests-printers-programs) or $(tests-printers-out),
71 as required. Pass $(tests-printers) to merge-test-results.sh.
72 * manual/install.texi: Add requirements for testing the pretty printers.
73 * nptl/Makefile (gen-py-const-headers, pretty-printers, tests-printers,
74 CFLAGS-test-mutexattr-printers.c CFLAGS-test-mutex-printers.c,
75 CFLAGS-test-condattr-printers.c, CFLAGS-test-cond-printers.c,
76 CFLAGS-test-rwlockattr-printers.c CFLAGS-test-rwlock-printers.c,
77 tests-printers-libs): Define.
78 * nptl/nptl-printers.py: New file.
79 * nptl/nptl_lock_constants.pysym: Likewise.
80 * nptl/test-cond-printers.c: Likewise.
81 * nptl/test-cond-printers.py: Likewise.
82 * nptl/test-condattr-printers.c: Likewise.
83 * nptl/test-condattr-printers.py: Likewise.
84 * nptl/test-mutex-printers.c: Likewise.
85 * nptl/test-mutex-printers.py: Likewise.
86 * nptl/test-mutexattr-printers.c: Likewise.
87 * nptl/test-mutexattr-printers.py: Likewise.
88 * nptl/test-rwlock-printers.c: Likewise.
89 * nptl/test-rwlock-printers.py: Likewise.
90 * nptl/test-rwlockattr-printers.c: Likewise.
91 * nptl/test-rwlockattr-printers.py: Likewise.
92 * scripts/gen-py-const.awk: Likewise.
93 * scripts/test_printers_common.py: Likewise.
94 * scripts/test_printers_exceptions.py: Likewise.
95
96Upstream-Status: Backport
97
98Author: Martin Galvan <martin.galvan@tallertechnologies.com>
99Signed-off-by: Catalin Enache <catalin.enache@windriver.com>
100---
101 ChangeLog | 45 +++
102 INSTALL | 27 ++
103 Makeconfig | 76 ++++-
104 Makerules | 46 +++
105 NEWS | 6 +
106 README.pretty-printers | 169 ++++++++++
107 Rules | 44 ++-
108 manual/install.texi | 30 ++
109 nptl/Makefile | 18 +
110 nptl/nptl-printers.py | 633 ++++++++++++++++++++++++++++++++++++
111 nptl/nptl_lock_constants.pysym | 75 +++++
112 nptl/test-cond-printers.c | 57 ++++
113 nptl/test-cond-printers.py | 50 +++
114 nptl/test-condattr-printers.c | 94 ++++++
115 nptl/test-condattr-printers.py | 71 ++++
116 nptl/test-mutex-printers.c | 151 +++++++++
117 nptl/test-mutex-printers.py | 97 ++++++
118 nptl/test-mutexattr-printers.c | 144 ++++++++
119 nptl/test-mutexattr-printers.py | 101 ++++++
120 nptl/test-rwlock-printers.c | 78 +++++
121 nptl/test-rwlock-printers.py | 64 ++++
122 nptl/test-rwlockattr-printers.c | 98 ++++++
123 nptl/test-rwlockattr-printers.py | 73 +++++
124 scripts/gen-py-const.awk | 118 +++++++
125 scripts/test_printers_common.py | 364 +++++++++++++++++++++
126 scripts/test_printers_exceptions.py | 61 ++++
127 26 files changed, 2770 insertions(+), 20 deletions(-)
128 create mode 100644 README.pretty-printers
129 create mode 100644 nptl/nptl-printers.py
130 create mode 100644 nptl/nptl_lock_constants.pysym
131 create mode 100644 nptl/test-cond-printers.c
132 create mode 100644 nptl/test-cond-printers.py
133 create mode 100644 nptl/test-condattr-printers.c
134 create mode 100644 nptl/test-condattr-printers.py
135 create mode 100644 nptl/test-mutex-printers.c
136 create mode 100644 nptl/test-mutex-printers.py
137 create mode 100644 nptl/test-mutexattr-printers.c
138 create mode 100644 nptl/test-mutexattr-printers.py
139 create mode 100644 nptl/test-rwlock-printers.c
140 create mode 100644 nptl/test-rwlock-printers.py
141 create mode 100644 nptl/test-rwlockattr-printers.c
142 create mode 100644 nptl/test-rwlockattr-printers.py
143 create mode 100644 scripts/gen-py-const.awk
144 create mode 100644 scripts/test_printers_common.py
145 create mode 100644 scripts/test_printers_exceptions.py
146
147diff --git a/ChangeLog b/ChangeLog
148index 96b6da2..8036c1e 100644
149--- a/ChangeLog
150+++ b/ChangeLog
151@@ -1,3 +1,48 @@
152+2016-12-08 Martin Galvan <martin.galvan@tallertechnologies.com>
153+
154+ * INSTALL: Regenerated.
155+ * Makeconfig: Add comments and whitespace to make the control flow
156+ clearer.
157+ (+link-printers-tests, +link-pie-printers-tests,
158+ CFLAGS-printers-tests, installed-rtld-LDFLAGS,
159+ built-rtld-LDFLAGS, link-libc-rpath,
160+ link-libc-tests-after-rpath-link,
161+ link-libc-printers-tests): New.
162+ (rtld-LDFLAGS, rtld-tests-LDFLAGS, link-libc-tests-rpath-link,
163+ link-libc-tests): Use the new variables as required.
164+ * Makerules ($(py-const)): New rule.
165+ generated: Add $(py-const).
166+ * README.pretty-printers: New file.
167+ * Rules (tests-printers-programs, tests-printers-out, py-env): New.
168+ (others): Depend on $(py-const).
169+ (tests): Depend on $(tests-printers-programs) or
170+ $(tests-printers-out),
171+ as required. Pass $(tests-printers) to merge-test-results.sh.
172+ * manual/install.texi: Add requirements for testing the pretty
173+ printers.
174+ * nptl/Makefile (gen-py-const-headers, pretty-printers,
175+ tests-printers, CFLAGS-test-mutexattr-printers.c
176+ CFLAGS-test-mutex-printers.c, CFLAGS-test-condattr-printers.c,
177+ CFLAGS-test-cond-printers.c, CFLAGS-test-rwlockattr-printers.c
178+ CFLAGS-test-rwlock-printers.c, tests-printers-libs): Define.
179+ * nptl/nptl-printers.py: New file.
180+ * nptl/nptl_lock_constants.pysym: Likewise.
181+ * nptl/test-cond-printers.c: Likewise.
182+ * nptl/test-cond-printers.py: Likewise.
183+ * nptl/test-condattr-printers.c: Likewise.
184+ * nptl/test-condattr-printers.py: Likewise.
185+ * nptl/test-mutex-printers.c: Likewise.
186+ * nptl/test-mutex-printers.py: Likewise.
187+ * nptl/test-mutexattr-printers.c: Likewise.
188+ * nptl/test-mutexattr-printers.py: Likewise.
189+ * nptl/test-rwlock-printers.c: Likewise.
190+ * nptl/test-rwlock-printers.py: Likewise.
191+ * nptl/test-rwlockattr-printers.c: Likewise.
192+ * nptl/test-rwlockattr-printers.py: Likewise.
193+ * scripts/gen-py-const.awk: Likewise.
194+ * scripts/test_printers_common.py: Likewise.
195+ * scripts/test_printers_exceptions.py: Likewise.
196+
197 2016-08-09 Torvald Riegel <triegel@redhat.com>
198
199 * include/atomic.h (atomic_fetch_and_relaxed,
200diff --git a/INSTALL b/INSTALL
201index ec3445f..dd62c86 100644
202--- a/INSTALL
203+++ b/INSTALL
204@@ -224,6 +224,33 @@ You can specify 'stop-on-test-failure=y' when running 'make check' to
205 make the test run stop and exit with an error status immediately when a
206 failure occurs.
207
208+ The GNU C Library pretty printers come with their own set of scripts
209+for testing, which run together with the rest of the testsuite through
210+'make check'. These scripts require the following tools to run
211+successfully:
212+
213+ * Python 2.7.6/3.4.3 or later
214+
215+ Python is required for running the printers' test scripts.
216+
217+ * PExpect 4.0
218+
219+ The printer tests drive GDB through test programs and compare its
220+ output to the printers'. PExpect is used to capture the output of
221+ GDB, and should be compatible with the Python version in your
222+ system.
223+
224+ * GDB 7.8 or later with support for Python 2.7.6/3.4.3 or later
225+
226+ GDB itself needs to be configured with Python support in order to
227+ use the pretty printers. Notice that your system having Python
228+ available doesn't imply that GDB supports it, nor that your
229+ system's Python and GDB's have the same version.
230+
231+If these tools are absent, the printer tests will report themselves as
232+'UNSUPPORTED'. Notice that some of the printer tests require the GNU C
233+Library to be compiled with debugging symbols.
234+
235 To format the 'GNU C Library Reference Manual' for printing, type
236 'make dvi'. You need a working TeX installation to do this. The
237 distribution builds the on-line formatted version of the manual, as Info
238diff --git a/Makeconfig b/Makeconfig
239index 03fd89c..2d92d94 100644
240--- a/Makeconfig
241+++ b/Makeconfig
242@@ -416,6 +416,11 @@ $(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
243 $(+link-pie-after-libc)
244 $(call after-link,$@)
245 endef
246+define +link-pie-printers-tests
247+$(+link-pie-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \
248+ $(+link-pie-after-libc)
249+$(call after-link,$@)
250+endef
251 endif
252 # Command for statically linking programs with the C library.
253 ifndef +link-static
254@@ -445,7 +450,8 @@ ifeq (yes,$(build-pie-default))
255 no-pie-ldflag = -no-pie
256 +link = $(+link-pie)
257 +link-tests = $(+link-pie-tests)
258-else
259++link-printers-tests = $(+link-pie-printers-tests)
260+else # not build-pie-default
261 +link-before-libc = $(CC) -nostdlib -nostartfiles -o $@ \
262 $(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
263 $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
264@@ -466,51 +472,87 @@ $(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
265 $(+link-after-libc)
266 $(call after-link,$@)
267 endef
268-endif
269-else
270+define +link-printers-tests
271+$(+link-before-libc) $(built-rtld-LDFLAGS) $(link-libc-printers-tests) \
272+ $(+link-after-libc)
273+$(call after-link,$@)
274+endef
275+endif # build-pie-default
276+else # build-static
277 +link = $(+link-static)
278 +link-tests = $(+link-static-tests)
279-endif
280-endif
281++link-printers-tests = $(+link-static-tests)
282+endif # build-shared
283+endif # +link
284+
285+# The pretty printer test programs need to be compiled without optimizations
286+# so they won't confuse gdb. We could use either the 'GCC optimize' pragma
287+# or the 'optimize' function attribute to achieve this; however, at least on
288+# ARM, gcc always produces different debugging symbols when invoked with
289+# a -O greater than 0 than when invoked with -O0, regardless of anything else
290+# we're using to suppress optimizations. Therefore, we need to explicitly pass
291+# -O0 to it through CFLAGS.
292+# Additionally, the build system will try to -include $(common-objpfx)/config.h
293+# when compiling the tests, which will throw an error if some special macros
294+# (such as __OPTIMIZE__ and IS_IN_build) aren't defined. To avoid this, we
295+# tell gcc to define IS_IN_build.
296+CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build
297+
298 ifeq (yes,$(build-shared))
299+# These indicate whether to link using the built ld.so or the installed one.
300+installed-rtld-LDFLAGS = -Wl,-dynamic-linker=$(rtlddir)/$(rtld-installed-name)
301+built-rtld-LDFLAGS = -Wl,-dynamic-linker=$(elf-objpfx)ld.so
302+
303 ifndef rtld-LDFLAGS
304-rtld-LDFLAGS = -Wl,-dynamic-linker=$(rtlddir)/$(rtld-installed-name)
305+rtld-LDFLAGS = $(installed-rtld-LDFLAGS)
306 endif
307+
308 ifndef rtld-tests-LDFLAGS
309 ifeq (yes,$(build-hardcoded-path-in-tests))
310-rtld-tests-LDFLAGS = -Wl,-dynamic-linker=$(elf-objpfx)ld.so
311+rtld-tests-LDFLAGS = $(built-rtld-LDFLAGS)
312 else
313-rtld-tests-LDFLAGS = $(rtld-LDFLAGS)
314-endif
315-endif
316-endif
317+rtld-tests-LDFLAGS = $(installed-rtld-LDFLAGS)
318+endif # build-hardcoded-path-in-tests
319+endif # rtld-tests-LDFLAGS
320+
321+endif # build-shared
322+
323 ifndef link-libc
324 ifeq (yes,$(build-shared))
325 # We need the versioned name of libc.so in the deps of $(others) et al
326 # so that the symlink to libc.so is created before anything tries to
327 # run the linked programs.
328+link-libc-rpath = -Wl,-rpath=$(rpath-link)
329 link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
330+
331 ifeq (yes,$(build-hardcoded-path-in-tests))
332-link-libc-tests-rpath-link = -Wl,-rpath=$(rpath-link)
333+link-libc-tests-rpath-link = $(link-libc-rpath)
334 else
335 link-libc-tests-rpath-link = $(link-libc-rpath-link)
336-endif
337+endif # build-hardcoded-path-in-tests
338+
339 link-libc-before-gnulib = $(common-objpfx)libc.so$(libc.so-version) \
340 $(common-objpfx)$(patsubst %,$(libtype.oS),c) \
341 $(as-needed) $(elf-objpfx)ld.so \
342 $(no-as-needed)
343 link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib)
344+
345+link-libc-tests-after-rpath-link = $(link-libc-before-gnulib) $(gnulib-tests)
346 link-libc-tests = $(link-libc-tests-rpath-link) \
347- $(link-libc-before-gnulib) $(gnulib-tests)
348+ $(link-libc-tests-after-rpath-link)
349+# Pretty printer test programs always require rpath instead of rpath-link.
350+link-libc-printers-tests = $(link-libc-rpath) \
351+ $(link-libc-tests-after-rpath-link)
352+
353 # This is how to find at build-time things that will be installed there.
354 rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec
355 rpath-link = \
356 $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
357-else
358+else # build-static
359 link-libc = $(common-objpfx)libc.a $(otherlibs) $(gnulib) $(common-objpfx)libc.a $(gnulib)
360 link-libc-tests = $(common-objpfx)libc.a $(otherlibs) $(gnulib-tests) $(common-objpfx)libc.a $(gnulib-tests)
361-endif
362-endif
363+endif # build-shared
364+endif # link-libc
365
366 # Differences in the linkers on the various platforms.
367 LDFLAGS-rpath-ORIGIN = -Wl,-rpath,'$$ORIGIN'
368diff --git a/Makerules b/Makerules
369index be3c11b..b7e0f59 100644
370--- a/Makerules
371+++ b/Makerules
372@@ -214,6 +214,52 @@ sed-remove-dotdot := -e 's@ *\([^ \/$$][^ \]*\)@ $$(..)\1@g' \
373 -e 's@^\([^ \/$$][^ \]*\)@$$(..)\1@g'
374 endif
375
376+ifdef gen-py-const-headers
377+# We'll use a static pattern rule to match .pysym files with their
378+# corresponding generated .py files.
379+# The generated .py files go in the submodule's dir in the glibc build dir.
380+py-const-files := $(patsubst %.pysym,%.py,$(gen-py-const-headers))
381+py-const-dir := $(objpfx)
382+py-const := $(addprefix $(py-const-dir),$(py-const-files))
383+py-const-script := $(..)scripts/gen-py-const.awk
384+
385+# This is a hack we use to generate .py files with constants for Python
386+# pretty printers. It works the same way as gen-as-const.
387+# See scripts/gen-py-const.awk for details on how the awk | gcc mechanism
388+# works.
389+#
390+# $@.tmp and $@.tmp2 are temporary files we use to store the partial contents
391+# of the target file. We do this instead of just writing on $@ because, if the
392+# build process terminates prematurely, re-running Make wouldn't run this rule
393+# since Make would see that the target file already exists (despite it being
394+# incomplete).
395+#
396+# The sed line replaces "@name@SOME_NAME@value@SOME_VALUE@" strings from the
397+# output of 'gcc -S' with "SOME_NAME = SOME_VALUE" strings.
398+# The '-n' option, combined with the '/p' command, makes sed output only the
399+# modified lines instead of the whole input file. The output is redirected
400+# to a .py file; we'll import it in the pretty printers file to read
401+# the constants generated by gen-py-const.awk.
402+# The regex has two capturing groups, for SOME_NAME and SOME_VALUE
403+# respectively. Notice SOME_VALUE may be prepended by a special character,
404+# depending on the assembly syntax (e.g. immediates are prefixed by a '$'
405+# in AT&T x86, and by a '#' in ARM). We discard it using a complemented set
406+# before the second capturing group.
407+$(py-const): $(py-const-dir)%.py: %.pysym $(py-const-script) \
408+ $(common-before-compile)
409+ $(make-target-directory)
410+ $(AWK) -f $(py-const-script) $< \
411+ | $(CC) -S -o $@.tmp $(CFLAGS) $(CPPFLAGS) -x c -
412+ echo '# GENERATED FILE\n' > $@.tmp2
413+ echo '# Constant definitions for pretty printers.' >> $@.tmp2
414+ echo '# See gen-py-const.awk for details.\n' >> $@.tmp2
415+ sed -n -r 's/^.*@name@([^@]+)@value@[^[:xdigit:]Xx-]*([[:xdigit:]Xx-]+)@.*/\1 = \2/p' \
416+ $@.tmp >> $@.tmp2
417+ mv -f $@.tmp2 $@
418+ rm -f $@.tmp
419+
420+generated += $(py-const)
421+endif # gen-py-const-headers
422
423 ifdef gen-as-const-headers
424 # Generating headers for assembly constants.
425diff --git a/NEWS b/NEWS
426index b0447e7..3002773 100644
427--- a/NEWS
428+++ b/NEWS
429@@ -5,6 +5,12 @@ See the end for copying conditions.
430 Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
431 using `glibc' in the "product" field.
432
433+
434+* GDB pretty printers have been added for mutex and condition variable
435+ structures in POSIX Threads. When installed and loaded in gdb these pretty
436+ printers show various pthread variables in human-readable form when read
437+ using the 'print' or 'display' commands in gdb.
438+
439 Version 2.24
440
441 * The minimum Linux kernel version that this version of the GNU C Library
442diff --git a/README.pretty-printers b/README.pretty-printers
443new file mode 100644
444index 0000000..8662900
445--- /dev/null
446+++ b/README.pretty-printers
447@@ -0,0 +1,169 @@
448+README for the glibc Python pretty printers
449+===========================================
450+
451+Pretty printers are gdb extensions that allow it to print useful, human-readable
452+information about a program's variables. For example, for a pthread_mutex_t
453+gdb would usually output something like this:
454+
455+(gdb) print mutex
456+$1 = {
457+ __data = {
458+ __lock = 22020096,
459+ __count = 0,
460+ __owner = 0,
461+ __nusers = 0,
462+ __kind = 576,
463+ __spins = 0,
464+ __elision = 0,
465+ __list = {
466+ __prev = 0x0,
467+ __next = 0x0
468+ }
469+ },
470+ __size = "\000\000P\001", '\000' <repeats 12 times>, "@\002", '\000' <repeats 21 times>,
471+ __align = 22020096
472+}
473+
474+However, with a pretty printer gdb will output something like this:
475+
476+(gdb) print mutex
477+$1 = pthread_mutex_t = {
478+ Type = Normal,
479+ Status = Unlocked,
480+ Robust = No,
481+ Shared = No,
482+ Protocol = Priority protect,
483+ Priority ceiling = 42
484+}
485+
486+Before printing a value, gdb will first check if there's a pretty printer
487+registered for it. If there is, it'll use it, otherwise it'll print the value
488+as usual. Pretty printers can be registered in various ways; for our purposes
489+we register them for the current objfile by calling
490+gdb.printing.register_pretty_printer().
491+
492+Currently our printers are based on gdb.RegexpCollectionPrettyPrinter, which
493+means they'll be triggered if the type of the variable we're printing matches
494+a given regular expression. For example, MutexPrinter will be triggered if
495+our variable's type matches the regexp '^pthread_mutex_t$'.
496+
497+Besides the printers themselves, each module may have a constants file which the
498+printers will import. These constants are generated from C headers during the
499+build process, and need to be in the Python search path when loading the
500+printers.
501+
502+
503+Installing and loading
504+----------------------
505+
506+The pretty printers and their constant files may be installed in different paths
507+for each distro, though gdb should be able to automatically load them by itself.
508+When in doubt, you can use the 'info pretty-printer' gdb command to list the
509+loaded pretty printers.
510+
511+If the printers aren't automatically loaded for some reason, you should add the
512+following to your .gdbinit:
513+
514+python
515+import sys
516+sys.path.insert(0, '/path/to/constants/file/directory')
517+end
518+
519+source /path/to/printers.py
520+
521+If you're building glibc manually, '/path/to/constants/file/directory' should be
522+'/path/to/glibc-build/submodule', where 'submodule' is e.g. nptl.
523+
524+
525+Testing
526+-------
527+
528+The pretty printers come with a small test suite based on PExpect, which is a
529+Python module with Expect-like features for spawning and controlling interactive
530+programs. Each printer has a corresponding C program and a Python script
531+that uses PExpect to drive gdb through the program and compare its output to
532+the expected printer's.
533+
534+The tests run on the glibc host, which is assumed to have both gdb and PExpect;
535+if any of those is absent the tests will fail with code 77 (UNSUPPORTED).
536+Native builds can be tested simply by doing 'make check'; cross builds must use
537+cross-test-ssh.sh as test-wrapper, like this:
538+
539+make test-wrapper='/path/to/scripts/cross-test-ssh.sh user@host' check
540+
541+(Remember to share the build system's filesystem with the glibc host's through
542+NFS or something similar).
543+
544+Running 'make check' on a cross build will only compile the test programs,
545+without running the scripts.
546+
547+
548+Adding new pretty printers
549+--------------------------
550+
551+Adding new pretty printers to glibc requires following these steps:
552+
553+1. Identify which constants must be generated from C headers, and write the
554+corresponding .pysym file. See scripts/gen-py-const.awk for more information
555+on how this works. The name of the .pysym file must be added to the
556+'gen-py-const-headers' variable in your submodule's Makefile (without the .pysym
557+extension).
558+
559+2. Write the pretty printer code itself. For this you can follow the gdb
560+Python API documentation, and use the existing printers as examples. The printer
561+code must import the generated constants file (which will have the same name
562+as your .pysym file). The names of the pretty printer files must be added
563+to the 'pretty-printers' variable in your submodule's Makefile (without the .py
564+extension).
565+
566+3. Write the unit tests for your pretty printers. The build system calls each
567+test script passing it the paths to the test program source, the test program
568+binary, and the printer files you added to 'pretty-printers' in the previous
569+step. The test scripts, in turn, must import scripts/test_printers_common
570+and call the init_test function passing it, among other things, the name of the
571+set of pretty printers to enable (as seen by running 'info pretty-printer').
572+You can use the existing unit tests as examples.
573+
574+4. Add the names of the pretty printer tests to the 'tests-printers' variable
575+in your submodule's Makefile (without extensions). In addition, for each test
576+program you must define a corresponding CFLAGS-* variable and set it to
577+$(CFLAGS-printers-tests) to ensure they're compiled correctly. For example,
578+test-foo-printer.c requires the following:
579+
580+CFLAGS-test-foo-printer.c := $(CFLAGS-printers-tests)
581+
582+Finally, if your programs need to be linked with a specific library, you can add
583+its name to the 'tests-printers-libs' variable in your submodule's Makefile.
584+
585+
586+Known issues
587+------------
588+
589+* Pretty printers are inherently coupled to the code they're targetting, thus
590+any changes to the target code must also update the corresponding printers.
591+On the plus side, the printer code itself may serve as a kind of documentation
592+for the target code.
593+
594+* Older versions of the gdb Python API have a bug where
595+gdb.RegexpCollectionPrettyPrinter would not be able to get a value's real type
596+if it was typedef'd. This would cause gdb to ignore the pretty printers for
597+types like pthread_mutex_t, which is defined as:
598+
599+typedef union
600+{
601+ ...
602+} pthread_mutex_t;
603+
604+This was fixed in commit 1b588015839caafc608a6944a78aea170f5fb2f6, and released
605+as part of gdb 7.8. However, typedef'ing an already typedef'd type may cause
606+a similar issue, e.g.:
607+
608+typedef pthread_mutex_t mutex;
609+mutex a_mutex;
610+
611+Here, trying to print a_mutex won't trigger the pthread_mutex_t printer.
612+
613+* The test programs must be compiled without optimizations. This is necessary
614+because the test scripts rely on the C code structure being preserved when
615+stepping through the programs. Things like aggressive instruction reordering
616+or optimizing variables out may make this kind of testing impossible.
617diff --git a/Rules b/Rules
618index 8306d36..10a6479 100644
619--- a/Rules
620+++ b/Rules
621@@ -85,16 +85,27 @@ common-generated += dummy.o dummy.c
622
623 .PHONY: others tests bench bench-build
624
625+# Test programs for the pretty printers.
626+tests-printers-programs := $(addprefix $(objpfx),$(tests-printers))
627+
628+# .out files with the output of running the pretty printer tests.
629+tests-printers-out := $(patsubst %,$(objpfx)%.out,$(tests-printers))
630+
631 ifeq ($(build-programs),yes)
632 others: $(addprefix $(objpfx),$(others) $(sysdep-others) $(extra-objs))
633 else
634 others: $(addprefix $(objpfx),$(extra-objs))
635 endif
636+
637+# Generate constant files for Python pretty printers if required.
638+others: $(py-const)
639+
640 ifeq ($(run-built-tests),no)
641-tests: $(addprefix $(objpfx),$(tests) $(test-srcs)) $(tests-special)
642+tests: $(addprefix $(objpfx),$(tests) $(test-srcs)) $(tests-special) \
643+ $(tests-printers-programs)
644 xtests: tests $(xtests-special)
645 else
646-tests: $(tests:%=$(objpfx)%.out) $(tests-special)
647+tests: $(tests:%=$(objpfx)%.out) $(tests-special) $(tests-printers-out)
648 xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
649 endif
650
651@@ -102,7 +113,8 @@ tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
652 xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special))
653 tests:
654 $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
655- $(sort $(tests) $(tests-special-notdir:.out=)) \
656+ $(sort $(tests) $(tests-special-notdir:.out=) \
657+ $(tests-printers)) \
658 > $(objpfx)subdir-tests.sum
659 xtests:
660 $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
661@@ -212,6 +224,32 @@ endif
662
663 endif # tests
664
665+ifneq "$(strip $(tests-printers))" ""
666+# We're defining this here for now; later it'll be defined at configure time
667+# inside Makeconfig.
668+PYTHON := python
669+
670+# Static pattern rule for building the test programs for the pretty printers.
671+$(tests-printers-programs): %: %.o $(tests-printers-libs) \
672+ $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \
673+ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
674+ $(+link-printers-tests)
675+
676+# Add the paths to the generated constants file and test_common_printers.py
677+# to PYTHONPATH so the test scripts can find them.
678+py-env := PYTHONPATH=$(py-const-dir):$(..)scripts:$${PYTHONPATH}
679+
680+# Static pattern rule that matches the test-* targets to their .c and .py
681+# prerequisites. It'll run the corresponding test script for each test program
682+# we compiled and place its output in the corresponding .out file.
683+# The pretty printer files and test_common_printers.py must be present for all.
684+$(tests-printers-out): $(objpfx)%.out: $(objpfx)% %.py %.c $(pretty-printers) \
685+ $(..)scripts/test_printers_common.py
686+ $(test-wrapper-env) $(py-env) \
687+ $(PYTHON) $*.py $*.c $(objpfx)$* $(pretty-printers) > $@; \
688+ $(evaluate-test)
689+endif
690+
691
692 .PHONY: distclean realclean subdir_distclean subdir_realclean \
693 subdir_clean subdir_mostlyclean subdir_testclean
694diff --git a/manual/install.texi b/manual/install.texi
695index 79ee45f..468479e 100644
696--- a/manual/install.texi
697+++ b/manual/install.texi
698@@ -256,6 +256,36 @@ occurred. You can specify @samp{stop-on-test-failure=y} when running
699 @code{make check} to make the test run stop and exit with an error
700 status immediately when a failure occurs.
701
702+The @glibcadj{} pretty printers come with their own set of scripts for testing,
703+which run together with the rest of the testsuite through @code{make check}.
704+These scripts require the following tools to run successfully:
705+
706+@itemize @bullet
707+@item
708+Python 2.7.6/3.4.3 or later
709+
710+Python is required for running the printers' test scripts.
711+
712+@item PExpect 4.0
713+
714+The printer tests drive GDB through test programs and compare its output
715+to the printers'. PExpect is used to capture the output of GDB, and should be
716+compatible with the Python version in your system.
717+
718+@item
719+GDB 7.8 or later with support for Python 2.7.6/3.4.3 or later
720+
721+GDB itself needs to be configured with Python support in order to use the
722+pretty printers. Notice that your system having Python available doesn't imply
723+that GDB supports it, nor that your system's Python and GDB's have the same
724+version.
725+@end itemize
726+
727+@noindent
728+If these tools are absent, the printer tests will report themselves as
729+@code{UNSUPPORTED}. Notice that some of the printer tests require @theglibc{}
730+to be compiled with debugging symbols.
731+
732 To format the @cite{GNU C Library Reference Manual} for printing, type
733 @w{@code{make dvi}}. You need a working @TeX{} installation to do
734 this. The distribution builds the on-line formatted version of the
735diff --git a/nptl/Makefile b/nptl/Makefile
736index 7dec4ed..49f6ba6 100644
737--- a/nptl/Makefile
738+++ b/nptl/Makefile
739@@ -308,6 +308,24 @@ gen-as-const-headers = pthread-errnos.sym \
740 unwindbuf.sym \
741 lowlevelrobustlock.sym pthread-pi-defines.sym
742
743+gen-py-const-headers := nptl_lock_constants.pysym
744+pretty-printers := nptl-printers.py
745+tests-printers := test-mutexattr-printers test-mutex-printers \
746+ test-condattr-printers test-cond-printers \
747+ test-rwlockattr-printers test-rwlock-printers
748+
749+CFLAGS-test-mutexattr-printers.c := $(CFLAGS-printers-tests)
750+CFLAGS-test-mutex-printers.c := $(CFLAGS-printers-tests)
751+CFLAGS-test-condattr-printers.c := $(CFLAGS-printers-tests)
752+CFLAGS-test-cond-printers.c := $(CFLAGS-printers-tests)
753+CFLAGS-test-rwlockattr-printers.c := $(CFLAGS-printers-tests)
754+CFLAGS-test-rwlock-printers.c := $(CFLAGS-printers-tests)
755+
756+ifeq ($(build-shared),yes)
757+tests-printers-libs := $(shared-thread-library)
758+else
759+tests-printers-libs := $(static-thread-library)
760+endif
761
762 LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
763
764diff --git a/nptl/nptl-printers.py b/nptl/nptl-printers.py
765new file mode 100644
766index 0000000..e402f23
767--- /dev/null
768+++ b/nptl/nptl-printers.py
769@@ -0,0 +1,633 @@
770+# Pretty printers for the NPTL lock types.
771+#
772+# Copyright (C) 2016 Free Software Foundation, Inc.
773+# This file is part of the GNU C Library.
774+#
775+# The GNU C Library is free software; you can redistribute it and/or
776+# modify it under the terms of the GNU Lesser General Public
777+# License as published by the Free Software Foundation; either
778+# version 2.1 of the License, or (at your option) any later version.
779+#
780+# The GNU C Library is distributed in the hope that it will be useful,
781+# but WITHOUT ANY WARRANTY; without even the implied warranty of
782+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
783+# Lesser General Public License for more details.
784+#
785+# You should have received a copy of the GNU Lesser General Public
786+# License along with the GNU C Library; if not, see
787+# <http://www.gnu.org/licenses/>.
788+
789+"""This file contains the gdb pretty printers for the following types:
790+
791+ * pthread_mutex_t
792+ * pthread_mutexattr_t
793+ * pthread_cond_t
794+ * pthread_condattr_t
795+ * pthread_rwlock_t
796+ * pthread_rwlockattr_t
797+
798+You can check which printers are registered and enabled by issuing the
799+'info pretty-printer' gdb command. Printers should trigger automatically when
800+trying to print a variable of one of the types mentioned above.
801+"""
802+
803+from __future__ import print_function
804+
805+import gdb
806+import gdb.printing
807+from nptl_lock_constants import *
808+
809+MUTEX_TYPES = {
810+ PTHREAD_MUTEX_NORMAL: ('Type', 'Normal'),
811+ PTHREAD_MUTEX_RECURSIVE: ('Type', 'Recursive'),
812+ PTHREAD_MUTEX_ERRORCHECK: ('Type', 'Error check'),
813+ PTHREAD_MUTEX_ADAPTIVE_NP: ('Type', 'Adaptive')
814+}
815+
816+class MutexPrinter(object):
817+ """Pretty printer for pthread_mutex_t."""
818+
819+ def __init__(self, mutex):
820+ """Initialize the printer's internal data structures.
821+
822+ Args:
823+ mutex: A gdb.value representing a pthread_mutex_t.
824+ """
825+
826+ data = mutex['__data']
827+ self.lock = data['__lock']
828+ self.count = data['__count']
829+ self.owner = data['__owner']
830+ self.kind = data['__kind']
831+ self.values = []
832+ self.read_values()
833+
834+ def to_string(self):
835+ """gdb API function.
836+
837+ This is called from gdb when we try to print a pthread_mutex_t.
838+ """
839+
840+ return 'pthread_mutex_t'
841+
842+ def children(self):
843+ """gdb API function.
844+
845+ This is called from gdb when we try to print a pthread_mutex_t.
846+ """
847+
848+ return self.values
849+
850+ def read_values(self):
851+ """Read the mutex's info and store it in self.values.
852+
853+ The data contained in self.values will be returned by the Iterator
854+ created in self.children.
855+ """
856+
857+ self.read_type()
858+ self.read_status()
859+ self.read_attributes()
860+ self.read_misc_info()
861+
862+ def read_type(self):
863+ """Read the mutex's type."""
864+
865+ mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
866+
867+ # mutex_type must be casted to int because it's a gdb.Value
868+ self.values.append(MUTEX_TYPES[int(mutex_type)])
869+
870+ def read_status(self):
871+ """Read the mutex's status.
872+
873+ For architectures which support lock elision, this method reads
874+ whether the mutex appears as locked in memory (i.e. it may show it as
875+ unlocked even after calling pthread_mutex_lock).
876+ """
877+
878+ if self.kind == PTHREAD_MUTEX_DESTROYED:
879+ self.values.append(('Status', 'Destroyed'))
880+ elif self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
881+ self.read_status_robust()
882+ else:
883+ self.read_status_no_robust()
884+
885+ def read_status_robust(self):
886+ """Read the status of a robust mutex.
887+
888+ In glibc robust mutexes are implemented in a very different way than
889+ non-robust ones. This method reads their locking status,
890+ whether it may have waiters, their registered owner (if any),
891+ whether the owner is alive or not, and the status of the state
892+ they're protecting.
893+ """
894+
895+ if self.lock == PTHREAD_MUTEX_UNLOCKED:
896+ self.values.append(('Status', 'Unlocked'))
897+ else:
898+ if self.lock & FUTEX_WAITERS:
899+ self.values.append(('Status', 'Locked, possibly with waiters'))
900+ else:
901+ self.values.append(('Status',
902+ 'Locked, possibly with no waiters'))
903+
904+ if self.lock & FUTEX_OWNER_DIED:
905+ self.values.append(('Owner ID', '%d (dead)' % self.owner))
906+ else:
907+ self.values.append(('Owner ID', self.lock & FUTEX_TID_MASK))
908+
909+ if self.owner == PTHREAD_MUTEX_INCONSISTENT:
910+ self.values.append(('State protected by this mutex',
911+ 'Inconsistent'))
912+ elif self.owner == PTHREAD_MUTEX_NOTRECOVERABLE:
913+ self.values.append(('State protected by this mutex',
914+ 'Not recoverable'))
915+
916+ def read_status_no_robust(self):
917+ """Read the status of a non-robust mutex.
918+
919+ Read info on whether the mutex is locked, if it may have waiters
920+ and its owner (if any).
921+ """
922+
923+ lock_value = self.lock
924+
925+ if self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
926+ lock_value &= ~(PTHREAD_MUTEX_PRIO_CEILING_MASK)
927+
928+ if lock_value == PTHREAD_MUTEX_UNLOCKED:
929+ self.values.append(('Status', 'Unlocked'))
930+ else:
931+ if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
932+ waiters = self.lock & FUTEX_WAITERS
933+ owner = self.lock & FUTEX_TID_MASK
934+ else:
935+ # Mutex protocol is PP or none
936+ waiters = (self.lock != PTHREAD_MUTEX_LOCKED_NO_WAITERS)
937+ owner = self.owner
938+
939+ if waiters:
940+ self.values.append(('Status', 'Locked, possibly with waiters'))
941+ else:
942+ self.values.append(('Status',
943+ 'Locked, possibly with no waiters'))
944+
945+ self.values.append(('Owner ID', owner))
946+
947+ def read_attributes(self):
948+ """Read the mutex's attributes."""
949+
950+ if self.kind != PTHREAD_MUTEX_DESTROYED:
951+ if self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
952+ self.values.append(('Robust', 'Yes'))
953+ else:
954+ self.values.append(('Robust', 'No'))
955+
956+ # In glibc, robust mutexes always have their pshared flag set to
957+ # 'shared' regardless of what the pshared flag of their
958+ # mutexattr was. Therefore a robust mutex will act as shared
959+ # even if it was initialized with a 'private' mutexattr.
960+ if self.kind & PTHREAD_MUTEX_PSHARED_BIT:
961+ self.values.append(('Shared', 'Yes'))
962+ else:
963+ self.values.append(('Shared', 'No'))
964+
965+ if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
966+ self.values.append(('Protocol', 'Priority inherit'))
967+ elif self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
968+ prio_ceiling = ((self.lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
969+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT)
970+
971+ self.values.append(('Protocol', 'Priority protect'))
972+ self.values.append(('Priority ceiling', prio_ceiling))
973+ else:
974+ # PTHREAD_PRIO_NONE
975+ self.values.append(('Protocol', 'None'))
976+
977+ def read_misc_info(self):
978+ """Read miscellaneous info on the mutex.
979+
980+ For now this reads the number of times a recursive mutex was locked
981+ by the same thread.
982+ """
983+
984+ mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
985+
986+ if mutex_type == PTHREAD_MUTEX_RECURSIVE and self.count > 1:
987+ self.values.append(('Times locked recursively', self.count))
988+
989+class MutexAttributesPrinter(object):
990+ """Pretty printer for pthread_mutexattr_t.
991+
992+ In the NPTL this is a type that's always casted to struct pthread_mutexattr
993+ which has a single 'mutexkind' field containing the actual attributes.
994+ """
995+
996+ def __init__(self, mutexattr):
997+ """Initialize the printer's internal data structures.
998+
999+ Args:
1000+ mutexattr: A gdb.value representing a pthread_mutexattr_t.
1001+ """
1002+
1003+ self.values = []
1004+
1005+ try:
1006+ mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr')
1007+ self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind']
1008+ self.read_values()
1009+ except gdb.error:
1010+ # libpthread doesn't have debug symbols, thus we can't find the
1011+ # real struct type. Just print the union members.
1012+ self.values.append(('__size', mutexattr['__size']))
1013+ self.values.append(('__align', mutexattr['__align']))
1014+
1015+ def to_string(self):
1016+ """gdb API function.
1017+
1018+ This is called from gdb when we try to print a pthread_mutexattr_t.
1019+ """
1020+
1021+ return 'pthread_mutexattr_t'
1022+
1023+ def children(self):
1024+ """gdb API function.
1025+
1026+ This is called from gdb when we try to print a pthread_mutexattr_t.
1027+ """
1028+
1029+ return self.values
1030+
1031+ def read_values(self):
1032+ """Read the mutexattr's info and store it in self.values.
1033+
1034+ The data contained in self.values will be returned by the Iterator
1035+ created in self.children.
1036+ """
1037+
1038+ mutexattr_type = (self.mutexattr
1039+ & ~PTHREAD_MUTEXATTR_FLAG_BITS
1040+ & ~PTHREAD_MUTEX_NO_ELISION_NP)
1041+
1042+ # mutexattr_type must be casted to int because it's a gdb.Value
1043+ self.values.append(MUTEX_TYPES[int(mutexattr_type)])
1044+
1045+ if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_ROBUST:
1046+ self.values.append(('Robust', 'Yes'))
1047+ else:
1048+ self.values.append(('Robust', 'No'))
1049+
1050+ if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
1051+ self.values.append(('Shared', 'Yes'))
1052+ else:
1053+ self.values.append(('Shared', 'No'))
1054+
1055+ protocol = ((self.mutexattr & PTHREAD_MUTEXATTR_PROTOCOL_MASK) >>
1056+ PTHREAD_MUTEXATTR_PROTOCOL_SHIFT)
1057+
1058+ if protocol == PTHREAD_PRIO_NONE:
1059+ self.values.append(('Protocol', 'None'))
1060+ elif protocol == PTHREAD_PRIO_INHERIT:
1061+ self.values.append(('Protocol', 'Priority inherit'))
1062+ elif protocol == PTHREAD_PRIO_PROTECT:
1063+ self.values.append(('Protocol', 'Priority protect'))
1064+
1065+CLOCK_IDS = {
1066+ CLOCK_REALTIME: 'CLOCK_REALTIME',
1067+ CLOCK_MONOTONIC: 'CLOCK_MONOTONIC',
1068+ CLOCK_PROCESS_CPUTIME_ID: 'CLOCK_PROCESS_CPUTIME_ID',
1069+ CLOCK_THREAD_CPUTIME_ID: 'CLOCK_THREAD_CPUTIME_ID',
1070+ CLOCK_MONOTONIC_RAW: 'CLOCK_MONOTONIC_RAW',
1071+ CLOCK_REALTIME_COARSE: 'CLOCK_REALTIME_COARSE',
1072+ CLOCK_MONOTONIC_COARSE: 'CLOCK_MONOTONIC_COARSE'
1073+}
1074+
1075+class ConditionVariablePrinter(object):
1076+ """Pretty printer for pthread_cond_t."""
1077+
1078+ def __init__(self, cond):
1079+ """Initialize the printer's internal data structures.
1080+
1081+ Args:
1082+ cond: A gdb.value representing a pthread_cond_t.
1083+ """
1084+
1085+ # Since PTHREAD_COND_SHARED is an integer, we need to cast it to void *
1086+ # to be able to compare it to the condvar's __data.__mutex member.
1087+ #
1088+ # While it looks like self.shared_value should be a class variable,
1089+ # that would result in it having an incorrect size if we're loading
1090+ # these printers through .gdbinit for a 64-bit objfile in AMD64.
1091+ # This is because gdb initially assumes the pointer size to be 4 bytes,
1092+ # and only sets it to 8 after loading the 64-bit objfiles. Since
1093+ # .gdbinit runs before any objfiles are loaded, this would effectively
1094+ # make self.shared_value have a size of 4, thus breaking later
1095+ # comparisons with pointers whose types are looked up at runtime.
1096+ void_ptr_type = gdb.lookup_type('void').pointer()
1097+ self.shared_value = gdb.Value(PTHREAD_COND_SHARED).cast(void_ptr_type)
1098+
1099+ data = cond['__data']
1100+ self.total_seq = data['__total_seq']
1101+ self.mutex = data['__mutex']
1102+ self.nwaiters = data['__nwaiters']
1103+ self.values = []
1104+
1105+ self.read_values()
1106+
1107+ def to_string(self):
1108+ """gdb API function.
1109+
1110+ This is called from gdb when we try to print a pthread_cond_t.
1111+ """
1112+
1113+ return 'pthread_cond_t'
1114+
1115+ def children(self):
1116+ """gdb API function.
1117+
1118+ This is called from gdb when we try to print a pthread_cond_t.
1119+ """
1120+
1121+ return self.values
1122+
1123+ def read_values(self):
1124+ """Read the condvar's info and store it in self.values.
1125+
1126+ The data contained in self.values will be returned by the Iterator
1127+ created in self.children.
1128+ """
1129+
1130+ self.read_status()
1131+ self.read_attributes()
1132+ self.read_mutex_info()
1133+
1134+ def read_status(self):
1135+ """Read the status of the condvar.
1136+
1137+ This method reads whether the condvar is destroyed and how many threads
1138+ are waiting for it.
1139+ """
1140+
1141+ if self.total_seq == PTHREAD_COND_DESTROYED:
1142+ self.values.append(('Status', 'Destroyed'))
1143+
1144+ self.values.append(('Threads waiting for this condvar',
1145+ self.nwaiters >> COND_NWAITERS_SHIFT))
1146+
1147+ def read_attributes(self):
1148+ """Read the condvar's attributes."""
1149+
1150+ clock_id = self.nwaiters & ((1 << COND_NWAITERS_SHIFT) - 1)
1151+
1152+ # clock_id must be casted to int because it's a gdb.Value
1153+ self.values.append(('Clock ID', CLOCK_IDS[int(clock_id)]))
1154+
1155+ shared = (self.mutex == self.shared_value)
1156+
1157+ if shared:
1158+ self.values.append(('Shared', 'Yes'))
1159+ else:
1160+ self.values.append(('Shared', 'No'))
1161+
1162+ def read_mutex_info(self):
1163+ """Read the data of the mutex this condvar is bound to.
1164+
1165+ A pthread_cond_t's __data.__mutex member is a void * which
1166+ must be casted to pthread_mutex_t *. For shared condvars, this
1167+ member isn't recorded and has a special value instead.
1168+ """
1169+
1170+ if self.mutex and self.mutex != self.shared_value:
1171+ mutex_type = gdb.lookup_type('pthread_mutex_t')
1172+ mutex = self.mutex.cast(mutex_type.pointer()).dereference()
1173+
1174+ self.values.append(('Mutex', mutex))
1175+
1176+class ConditionVariableAttributesPrinter(object):
1177+ """Pretty printer for pthread_condattr_t.
1178+
1179+ In the NPTL this is a type that's always casted to struct pthread_condattr,
1180+ which has a single 'value' field containing the actual attributes.
1181+ """
1182+
1183+ def __init__(self, condattr):
1184+ """Initialize the printer's internal data structures.
1185+
1186+ Args:
1187+ condattr: A gdb.value representing a pthread_condattr_t.
1188+ """
1189+
1190+ self.values = []
1191+
1192+ try:
1193+ condattr_struct = gdb.lookup_type('struct pthread_condattr')
1194+ self.condattr = condattr.cast(condattr_struct)['value']
1195+ self.read_values()
1196+ except gdb.error:
1197+ # libpthread doesn't have debug symbols, thus we can't find the
1198+ # real struct type. Just print the union members.
1199+ self.values.append(('__size', condattr['__size']))
1200+ self.values.append(('__align', condattr['__align']))
1201+
1202+ def to_string(self):
1203+ """gdb API function.
1204+
1205+ This is called from gdb when we try to print a pthread_condattr_t.
1206+ """
1207+
1208+ return 'pthread_condattr_t'
1209+
1210+ def children(self):
1211+ """gdb API function.
1212+
1213+ This is called from gdb when we try to print a pthread_condattr_t.
1214+ """
1215+
1216+ return self.values
1217+
1218+ def read_values(self):
1219+ """Read the condattr's info and store it in self.values.
1220+
1221+ The data contained in self.values will be returned by the Iterator
1222+ created in self.children.
1223+ """
1224+
1225+ clock_id = self.condattr & ((1 << COND_NWAITERS_SHIFT) - 1)
1226+
1227+ # clock_id must be casted to int because it's a gdb.Value
1228+ self.values.append(('Clock ID', CLOCK_IDS[int(clock_id)]))
1229+
1230+ if self.condattr & 1:
1231+ self.values.append(('Shared', 'Yes'))
1232+ else:
1233+ self.values.append(('Shared', 'No'))
1234+
1235+class RWLockPrinter(object):
1236+ """Pretty printer for pthread_rwlock_t."""
1237+
1238+ def __init__(self, rwlock):
1239+ """Initialize the printer's internal data structures.
1240+
1241+ Args:
1242+ rwlock: A gdb.value representing a pthread_rwlock_t.
1243+ """
1244+
1245+ data = rwlock['__data']
1246+ self.readers = data['__nr_readers']
1247+ self.queued_readers = data['__nr_readers_queued']
1248+ self.queued_writers = data['__nr_writers_queued']
1249+ self.writer_id = data['__writer']
1250+ self.shared = data['__shared']
1251+ self.prefers_writers = data['__flags']
1252+ self.values = []
1253+ self.read_values()
1254+
1255+ def to_string(self):
1256+ """gdb API function.
1257+
1258+ This is called from gdb when we try to print a pthread_rwlock_t.
1259+ """
1260+
1261+ return 'pthread_rwlock_t'
1262+
1263+ def children(self):
1264+ """gdb API function.
1265+
1266+ This is called from gdb when we try to print a pthread_rwlock_t.
1267+ """
1268+
1269+ return self.values
1270+
1271+ def read_values(self):
1272+ """Read the rwlock's info and store it in self.values.
1273+
1274+ The data contained in self.values will be returned by the Iterator
1275+ created in self.children.
1276+ """
1277+
1278+ self.read_status()
1279+ self.read_attributes()
1280+
1281+ def read_status(self):
1282+ """Read the status of the rwlock."""
1283+
1284+ # Right now pthread_rwlock_destroy doesn't do anything, so there's no
1285+ # way to check if an rwlock is destroyed.
1286+
1287+ if self.writer_id:
1288+ self.values.append(('Status', 'Locked (Write)'))
1289+ self.values.append(('Writer ID', self.writer_id))
1290+ elif self.readers:
1291+ self.values.append(('Status', 'Locked (Read)'))
1292+ self.values.append(('Readers', self.readers))
1293+ else:
1294+ self.values.append(('Status', 'Unlocked'))
1295+
1296+ self.values.append(('Queued readers', self.queued_readers))
1297+ self.values.append(('Queued writers', self.queued_writers))
1298+
1299+ def read_attributes(self):
1300+ """Read the attributes of the rwlock."""
1301+
1302+ if self.shared:
1303+ self.values.append(('Shared', 'Yes'))
1304+ else:
1305+ self.values.append(('Shared', 'No'))
1306+
1307+ if self.prefers_writers:
1308+ self.values.append(('Prefers', 'Writers'))
1309+ else:
1310+ self.values.append(('Prefers', 'Readers'))
1311+
1312+class RWLockAttributesPrinter(object):
1313+ """Pretty printer for pthread_rwlockattr_t.
1314+
1315+ In the NPTL this is a type that's always casted to
1316+ struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
1317+ containing the actual attributes.
1318+ """
1319+
1320+ def __init__(self, rwlockattr):
1321+ """Initialize the printer's internal data structures.
1322+
1323+ Args:
1324+ rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
1325+ """
1326+
1327+ self.values = []
1328+
1329+ try:
1330+ rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
1331+ self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
1332+ self.read_values()
1333+ except gdb.error:
1334+ # libpthread doesn't have debug symbols, thus we can't find the
1335+ # real struct type. Just print the union members.
1336+ self.values.append(('__size', rwlockattr['__size']))
1337+ self.values.append(('__align', rwlockattr['__align']))
1338+
1339+ def to_string(self):
1340+ """gdb API function.
1341+
1342+ This is called from gdb when we try to print a pthread_rwlockattr_t.
1343+ """
1344+
1345+ return 'pthread_rwlockattr_t'
1346+
1347+ def children(self):
1348+ """gdb API function.
1349+
1350+ This is called from gdb when we try to print a pthread_rwlockattr_t.
1351+ """
1352+
1353+ return self.values
1354+
1355+ def read_values(self):
1356+ """Read the rwlockattr's info and store it in self.values.
1357+
1358+ The data contained in self.values will be returned by the Iterator
1359+ created in self.children.
1360+ """
1361+
1362+ rwlock_type = self.rwlockattr['lockkind']
1363+ shared = self.rwlockattr['pshared']
1364+
1365+ if shared == PTHREAD_PROCESS_SHARED:
1366+ self.values.append(('Shared', 'Yes'))
1367+ else:
1368+ # PTHREAD_PROCESS_PRIVATE
1369+ self.values.append(('Shared', 'No'))
1370+
1371+ if (rwlock_type == PTHREAD_RWLOCK_PREFER_READER_NP or
1372+ rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NP):
1373+ # This is a known bug. Using PTHREAD_RWLOCK_PREFER_WRITER_NP will
1374+ # still make the rwlock prefer readers.
1375+ self.values.append(('Prefers', 'Readers'))
1376+ elif rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:
1377+ self.values.append(('Prefers', 'Writers'))
1378+
1379+def register(objfile):
1380+ """Register the pretty printers within the given objfile."""
1381+
1382+ printer = gdb.printing.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
1383+
1384+ printer.add_printer('pthread_mutex_t', r'^pthread_mutex_t$',
1385+ MutexPrinter)
1386+ printer.add_printer('pthread_mutexattr_t', r'^pthread_mutexattr_t$',
1387+ MutexAttributesPrinter)
1388+ printer.add_printer('pthread_cond_t', r'^pthread_cond_t$',
1389+ ConditionVariablePrinter)
1390+ printer.add_printer('pthread_condattr_t', r'^pthread_condattr_t$',
1391+ ConditionVariableAttributesPrinter)
1392+ printer.add_printer('pthread_rwlock_t', r'^pthread_rwlock_t$',
1393+ RWLockPrinter)
1394+ printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
1395+ RWLockAttributesPrinter)
1396+
1397+ if objfile == None:
1398+ objfile = gdb
1399+
1400+ gdb.printing.register_pretty_printer(objfile, printer)
1401+
1402+register(gdb.current_objfile())
1403diff --git a/nptl/nptl_lock_constants.pysym b/nptl/nptl_lock_constants.pysym
1404new file mode 100644
1405index 0000000..303ec61
1406--- /dev/null
1407+++ b/nptl/nptl_lock_constants.pysym
1408@@ -0,0 +1,75 @@
1409+#include <pthreadP.h>
1410+
1411+-- Mutex types
1412+PTHREAD_MUTEX_KIND_MASK PTHREAD_MUTEX_KIND_MASK_NP
1413+PTHREAD_MUTEX_NORMAL
1414+PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
1415+PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
1416+PTHREAD_MUTEX_ADAPTIVE_NP
1417+
1418+-- Mutex status
1419+-- These are hardcoded all over the code; there are no enums/macros for them.
1420+PTHREAD_MUTEX_DESTROYED -1
1421+PTHREAD_MUTEX_UNLOCKED 0
1422+PTHREAD_MUTEX_LOCKED_NO_WAITERS 1
1423+
1424+-- For robust mutexes
1425+PTHREAD_MUTEX_INCONSISTENT
1426+PTHREAD_MUTEX_NOTRECOVERABLE
1427+FUTEX_OWNER_DIED
1428+
1429+-- For robust and PI mutexes
1430+FUTEX_WAITERS
1431+FUTEX_TID_MASK
1432+
1433+-- Mutex attributes
1434+PTHREAD_MUTEX_ROBUST_NORMAL_NP
1435+PTHREAD_MUTEX_PRIO_INHERIT_NP
1436+PTHREAD_MUTEX_PRIO_PROTECT_NP
1437+PTHREAD_MUTEX_PSHARED_BIT
1438+PTHREAD_MUTEX_PRIO_CEILING_SHIFT
1439+PTHREAD_MUTEX_PRIO_CEILING_MASK
1440+
1441+-- Mutex attribute flags
1442+PTHREAD_MUTEXATTR_PROTOCOL_SHIFT
1443+PTHREAD_MUTEXATTR_PROTOCOL_MASK
1444+PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
1445+PTHREAD_MUTEXATTR_FLAG_ROBUST
1446+PTHREAD_MUTEXATTR_FLAG_PSHARED
1447+PTHREAD_MUTEXATTR_FLAG_BITS
1448+PTHREAD_MUTEX_NO_ELISION_NP
1449+
1450+-- Priority protocols
1451+PTHREAD_PRIO_NONE
1452+PTHREAD_PRIO_INHERIT
1453+PTHREAD_PRIO_PROTECT
1454+
1455+-- These values are hardcoded as well:
1456+-- Value of __mutex for shared condvars.
1457+PTHREAD_COND_SHARED (void *)~0l
1458+
1459+-- Value of __total_seq for destroyed condvars.
1460+PTHREAD_COND_DESTROYED -1ull
1461+
1462+-- __nwaiters encodes the number of threads waiting on a condvar
1463+-- and the clock ID.
1464+-- __nwaiters >> COND_NWAITERS_SHIFT gives us the number of waiters.
1465+COND_NWAITERS_SHIFT
1466+
1467+-- Condvar clock IDs
1468+CLOCK_REALTIME
1469+CLOCK_MONOTONIC
1470+CLOCK_PROCESS_CPUTIME_ID
1471+CLOCK_THREAD_CPUTIME_ID
1472+CLOCK_MONOTONIC_RAW
1473+CLOCK_REALTIME_COARSE
1474+CLOCK_MONOTONIC_COARSE
1475+
1476+-- Rwlock attributes
1477+PTHREAD_RWLOCK_PREFER_READER_NP
1478+PTHREAD_RWLOCK_PREFER_WRITER_NP
1479+PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
1480+
1481+-- 'Shared' attribute values
1482+PTHREAD_PROCESS_PRIVATE
1483+PTHREAD_PROCESS_SHARED
1484diff --git a/nptl/test-cond-printers.c b/nptl/test-cond-printers.c
1485new file mode 100644
1486index 0000000..0f2a5f4
1487--- /dev/null
1488+++ b/nptl/test-cond-printers.c
1489@@ -0,0 +1,57 @@
1490+/* Helper program for testing the pthread_cond_t pretty printer.
1491+
1492+ Copyright (C) 2016 Free Software Foundation, Inc.
1493+ This file is part of the GNU C Library.
1494+
1495+ The GNU C Library is free software; you can redistribute it and/or
1496+ modify it under the terms of the GNU Lesser General Public
1497+ License as published by the Free Software Foundation; either
1498+ version 2.1 of the License, or (at your option) any later version.
1499+
1500+ The GNU C Library is distributed in the hope that it will be useful,
1501+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1502+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1503+ Lesser General Public License for more details.
1504+
1505+ You should have received a copy of the GNU Lesser General Public
1506+ License along with the GNU C Library; if not, see
1507+ <http://www.gnu.org/licenses/>. */
1508+
1509+/* Keep the calls to the pthread_* functions on separate lines to make it easy
1510+ to advance through the program using the gdb 'next' command. */
1511+
1512+#include <time.h>
1513+#include <pthread.h>
1514+
1515+#define PASS 0
1516+#define FAIL 1
1517+
1518+static int test_status_destroyed (pthread_cond_t *condvar);
1519+
1520+int
1521+main (void)
1522+{
1523+ pthread_cond_t condvar;
1524+ pthread_condattr_t attr;
1525+ int result = FAIL;
1526+
1527+ if (pthread_condattr_init (&attr) == 0
1528+ && test_status_destroyed (&condvar) == PASS)
1529+ result = PASS;
1530+ /* Else, one of the pthread_cond* functions failed. */
1531+
1532+ return result;
1533+}
1534+
1535+/* Initializes CONDVAR, then destroys it. */
1536+static int
1537+test_status_destroyed (pthread_cond_t *condvar)
1538+{
1539+ int result = FAIL;
1540+
1541+ if (pthread_cond_init (condvar, NULL) == 0
1542+ && pthread_cond_destroy (condvar) == 0)
1543+ result = PASS; /* Test status (destroyed). */
1544+
1545+ return result;
1546+}
1547diff --git a/nptl/test-cond-printers.py b/nptl/test-cond-printers.py
1548new file mode 100644
1549index 0000000..af0e12e
1550--- /dev/null
1551+++ b/nptl/test-cond-printers.py
1552@@ -0,0 +1,50 @@
1553+# Common tests for the ConditionVariablePrinter class.
1554+#
1555+# Copyright (C) 2016 Free Software Foundation, Inc.
1556+# This file is part of the GNU C Library.
1557+#
1558+# The GNU C Library is free software; you can redistribute it and/or
1559+# modify it under the terms of the GNU Lesser General Public
1560+# License as published by the Free Software Foundation; either
1561+# version 2.1 of the License, or (at your option) any later version.
1562+#
1563+# The GNU C Library is distributed in the hope that it will be useful,
1564+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1565+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1566+# Lesser General Public License for more details.
1567+#
1568+# You should have received a copy of the GNU Lesser General Public
1569+# License along with the GNU C Library; if not, see
1570+# <http://www.gnu.org/licenses/>.
1571+
1572+import sys
1573+
1574+from test_printers_common import *
1575+
1576+test_source = sys.argv[1]
1577+test_bin = sys.argv[2]
1578+printer_files = sys.argv[3:]
1579+printer_names = ['global glibc-pthread-locks']
1580+
1581+try:
1582+ init_test(test_bin, printer_files, printer_names)
1583+ go_to_main()
1584+
1585+ var = 'condvar'
1586+ to_string = 'pthread_cond_t'
1587+
1588+ break_at(test_source, 'Test status (destroyed)')
1589+ continue_cmd() # Go to test_status_destroyed
1590+ test_printer(var, to_string, {'Status': 'Destroyed'})
1591+
1592+ continue_cmd() # Exit
1593+
1594+except (NoLineError, pexpect.TIMEOUT) as exception:
1595+ print('Error: {0}'.format(exception))
1596+ result = FAIL
1597+
1598+else:
1599+ print('Test succeeded.')
1600+ result = PASS
1601+
1602+exit(result)
1603diff --git a/nptl/test-condattr-printers.c b/nptl/test-condattr-printers.c
1604new file mode 100644
1605index 0000000..4db4098
1606--- /dev/null
1607+++ b/nptl/test-condattr-printers.c
1608@@ -0,0 +1,94 @@
1609+/* Helper program for testing the pthread_cond_t and pthread_condattr_t
1610+ pretty printers.
1611+
1612+ Copyright (C) 2016 Free Software Foundation, Inc.
1613+ This file is part of the GNU C Library.
1614+
1615+ The GNU C Library is free software; you can redistribute it and/or
1616+ modify it under the terms of the GNU Lesser General Public
1617+ License as published by the Free Software Foundation; either
1618+ version 2.1 of the License, or (at your option) any later version.
1619+
1620+ The GNU C Library is distributed in the hope that it will be useful,
1621+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1622+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1623+ Lesser General Public License for more details.
1624+
1625+ You should have received a copy of the GNU Lesser General Public
1626+ License along with the GNU C Library; if not, see
1627+ <http://www.gnu.org/licenses/>. */
1628+
1629+/* Keep the calls to the pthread_* functions on separate lines to make it easy
1630+ to advance through the program using the gdb 'next' command. */
1631+
1632+#include <time.h>
1633+#include <pthread.h>
1634+
1635+#define PASS 0
1636+#define FAIL 1
1637+
1638+static int condvar_reinit (pthread_cond_t *condvar,
1639+ const pthread_condattr_t *attr);
1640+static int test_setclock (pthread_cond_t *condvar, pthread_condattr_t *attr);
1641+static int test_setpshared (pthread_cond_t *condvar, pthread_condattr_t *attr);
1642+
1643+/* Need these so we don't have lines longer than 79 chars. */
1644+#define SET_SHARED(attr, shared) pthread_condattr_setpshared (attr, shared)
1645+
1646+int
1647+main (void)
1648+{
1649+ pthread_cond_t condvar;
1650+ pthread_condattr_t attr;
1651+ int result = FAIL;
1652+
1653+ if (pthread_condattr_init (&attr) == 0
1654+ && pthread_cond_init (&condvar, NULL) == 0
1655+ && test_setclock (&condvar, &attr) == PASS
1656+ && test_setpshared (&condvar, &attr) == PASS)
1657+ result = PASS;
1658+ /* Else, one of the pthread_cond* functions failed. */
1659+
1660+ return result;
1661+}
1662+
1663+/* Destroys CONDVAR and re-initializes it using ATTR. */
1664+static int
1665+condvar_reinit (pthread_cond_t *condvar, const pthread_condattr_t *attr)
1666+{
1667+ int result = FAIL;
1668+
1669+ if (pthread_cond_destroy (condvar) == 0
1670+ && pthread_cond_init (condvar, attr) == 0)
1671+ result = PASS;
1672+
1673+ return result;
1674+}
1675+
1676+/* Tests setting the clock ID attribute. */
1677+static int
1678+test_setclock (pthread_cond_t *condvar, pthread_condattr_t *attr)
1679+{
1680+ int result = FAIL;
1681+
1682+ if (pthread_condattr_setclock (attr, CLOCK_REALTIME) == 0 /* Set clock. */
1683+ && condvar_reinit (condvar, attr) == PASS)
1684+ result = PASS;
1685+
1686+ return result;
1687+}
1688+
1689+/* Tests setting whether the condvar can be shared between processes. */
1690+static int
1691+test_setpshared (pthread_cond_t *condvar, pthread_condattr_t *attr)
1692+{
1693+ int result = FAIL;
1694+
1695+ if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared. */
1696+ && condvar_reinit (condvar, attr) == PASS
1697+ && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
1698+ && condvar_reinit (condvar, attr) == PASS)
1699+ result = PASS;
1700+
1701+ return result;
1702+}
1703diff --git a/nptl/test-condattr-printers.py b/nptl/test-condattr-printers.py
1704new file mode 100644
1705index 0000000..7ea01db
1706--- /dev/null
1707+++ b/nptl/test-condattr-printers.py
1708@@ -0,0 +1,71 @@
1709+# Common tests for the ConditionVariablePrinter and
1710+# ConditionVariableAttributesPrinter classes.
1711+#
1712+# Copyright (C) 2016 Free Software Foundation, Inc.
1713+# This file is part of the GNU C Library.
1714+#
1715+# The GNU C Library is free software; you can redistribute it and/or
1716+# modify it under the terms of the GNU Lesser General Public
1717+# License as published by the Free Software Foundation; either
1718+# version 2.1 of the License, or (at your option) any later version.
1719+#
1720+# The GNU C Library is distributed in the hope that it will be useful,
1721+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1722+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1723+# Lesser General Public License for more details.
1724+#
1725+# You should have received a copy of the GNU Lesser General Public
1726+# License along with the GNU C Library; if not, see
1727+# <http://www.gnu.org/licenses/>.
1728+
1729+import sys
1730+
1731+from test_printers_common import *
1732+
1733+test_source = sys.argv[1]
1734+test_bin = sys.argv[2]
1735+printer_files = sys.argv[3:]
1736+printer_names = ['global glibc-pthread-locks']
1737+
1738+try:
1739+ init_test(test_bin, printer_files, printer_names)
1740+ go_to_main()
1741+
1742+ check_debug_symbol('struct pthread_condattr')
1743+
1744+ condvar_var = 'condvar'
1745+ condvar_to_string = 'pthread_cond_t'
1746+
1747+ attr_var = 'attr'
1748+ attr_to_string = 'pthread_condattr_t'
1749+
1750+ break_at(test_source, 'Set clock')
1751+ continue_cmd() # Go to test_setclock
1752+ next_cmd(2)
1753+ test_printer(condvar_var, condvar_to_string, {'Clock ID': 'CLOCK_REALTIME'})
1754+ test_printer(attr_var, attr_to_string, {'Clock ID': 'CLOCK_REALTIME'})
1755+
1756+ break_at(test_source, 'Set shared')
1757+ continue_cmd() # Go to test_setpshared
1758+ next_cmd(2)
1759+ test_printer(condvar_var, condvar_to_string, {'Shared': 'Yes'})
1760+ test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
1761+ next_cmd(2)
1762+ test_printer(condvar_var, condvar_to_string, {'Shared': 'No'})
1763+ test_printer(attr_var, attr_to_string, {'Shared': 'No'})
1764+
1765+ continue_cmd() # Exit
1766+
1767+except (NoLineError, pexpect.TIMEOUT) as exception:
1768+ print('Error: {0}'.format(exception))
1769+ result = FAIL
1770+
1771+except DebugError as exception:
1772+ print(exception)
1773+ result = UNSUPPORTED
1774+
1775+else:
1776+ print('Test succeeded.')
1777+ result = PASS
1778+
1779+exit(result)
1780diff --git a/nptl/test-mutex-printers.c b/nptl/test-mutex-printers.c
1781new file mode 100644
1782index 0000000..b973e82
1783--- /dev/null
1784+++ b/nptl/test-mutex-printers.c
1785@@ -0,0 +1,151 @@
1786+/* Helper program for testing the pthread_mutex_t pretty printer.
1787+
1788+ Copyright (C) 2016 Free Software Foundation, Inc.
1789+ This file is part of the GNU C Library.
1790+
1791+ The GNU C Library is free software; you can redistribute it and/or
1792+ modify it under the terms of the GNU Lesser General Public
1793+ License as published by the Free Software Foundation; either
1794+ version 2.1 of the License, or (at your option) any later version.
1795+
1796+ The GNU C Library is distributed in the hope that it will be useful,
1797+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1798+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1799+ Lesser General Public License for more details.
1800+
1801+ You should have received a copy of the GNU Lesser General Public
1802+ License along with the GNU C Library; if not, see
1803+ <http://www.gnu.org/licenses/>. */
1804+
1805+/* Keep the calls to the pthread_* functions on separate lines to make it easy
1806+ to advance through the program using the gdb 'next' command. */
1807+
1808+#include <stdlib.h>
1809+#include <errno.h>
1810+#include <pthread.h>
1811+
1812+#define PASS 0
1813+#define FAIL 1
1814+
1815+static int test_status_destroyed (pthread_mutex_t *mutex);
1816+static int test_status_no_robust (pthread_mutex_t *mutex,
1817+ pthread_mutexattr_t *attr);
1818+static int test_status_robust (pthread_mutex_t *mutex,
1819+ pthread_mutexattr_t *attr);
1820+static int test_locking_state_robust (pthread_mutex_t *mutex);
1821+static void *thread_func (void *arg);
1822+static int test_recursive_locks (pthread_mutex_t *mutex,
1823+ pthread_mutexattr_t *attr);
1824+
1825+int
1826+main (void)
1827+{
1828+ pthread_mutex_t mutex;
1829+ pthread_mutexattr_t attr;
1830+ int result = FAIL;
1831+
1832+ if (pthread_mutexattr_init (&attr) == 0
1833+ && test_status_destroyed (&mutex) == PASS
1834+ && test_status_no_robust (&mutex, &attr) == PASS
1835+ && test_status_robust (&mutex, &attr) == PASS
1836+ && test_recursive_locks (&mutex, &attr) == PASS)
1837+ result = PASS;
1838+ /* Else, one of the pthread_mutex* functions failed. */
1839+
1840+ return result;
1841+}
1842+
1843+/* Initializes MUTEX, then destroys it. */
1844+static int
1845+test_status_destroyed (pthread_mutex_t *mutex)
1846+{
1847+ int result = FAIL;
1848+
1849+ if (pthread_mutex_init (mutex, NULL) == 0
1850+ && pthread_mutex_destroy (mutex) == 0)
1851+ result = PASS; /* Test status (destroyed). */
1852+
1853+ return result;
1854+}
1855+
1856+/* Tests locking of non-robust mutexes. */
1857+static int
1858+test_status_no_robust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
1859+{
1860+ int result = FAIL;
1861+
1862+ if (pthread_mutexattr_setrobust (attr, PTHREAD_MUTEX_STALLED) == 0
1863+ && pthread_mutex_init (mutex, attr) == 0
1864+ && pthread_mutex_lock (mutex) == 0 /* Test status (non-robust). */
1865+ && pthread_mutex_unlock (mutex) == 0
1866+ && pthread_mutex_destroy (mutex) == 0)
1867+ result = PASS;
1868+
1869+ return result;
1870+}
1871+
1872+/* Tests locking of robust mutexes. */
1873+static int
1874+test_status_robust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
1875+{
1876+ int result = FAIL;
1877+
1878+ if (pthread_mutexattr_setrobust (attr, PTHREAD_MUTEX_ROBUST) == 0
1879+ && pthread_mutex_init (mutex, attr) == 0
1880+ && test_locking_state_robust (mutex) == PASS /* Test status (robust). */
1881+ && pthread_mutex_destroy (mutex) == 0)
1882+ result = PASS;
1883+
1884+ return result;
1885+}
1886+
1887+/* Tests locking and state corruption of robust mutexes. We'll mark it as
1888+ inconsistent, then not recoverable. */
1889+static int
1890+test_locking_state_robust (pthread_mutex_t *mutex)
1891+{
1892+ int result = FAIL;
1893+ pthread_t thread;
1894+
1895+ if (pthread_create (&thread, NULL, thread_func, mutex) == 0 /* Create. */
1896+ && pthread_join (thread, NULL) == 0
1897+ && pthread_mutex_lock (mutex) == EOWNERDEAD /* Test locking (robust). */
1898+ && pthread_mutex_unlock (mutex) == 0)
1899+ result = PASS;
1900+
1901+ return result;
1902+}
1903+
1904+/* Function to be called by the child thread when testing robust mutexes. */
1905+static void *
1906+thread_func (void *arg)
1907+{
1908+ pthread_mutex_t *mutex = (pthread_mutex_t *)arg;
1909+
1910+ if (pthread_mutex_lock (mutex) != 0) /* Thread function. */
1911+ exit (FAIL);
1912+
1913+ /* Thread terminates without unlocking the mutex, thus marking it as
1914+ inconsistent. */
1915+ return NULL;
1916+}
1917+
1918+/* Tests locking the mutex multiple times in a row. */
1919+static int
1920+test_recursive_locks (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
1921+{
1922+ int result = FAIL;
1923+
1924+ if (pthread_mutexattr_settype (attr, PTHREAD_MUTEX_RECURSIVE) == 0
1925+ && pthread_mutex_init (mutex, attr) == 0
1926+ && pthread_mutex_lock (mutex) == 0
1927+ && pthread_mutex_lock (mutex) == 0
1928+ && pthread_mutex_lock (mutex) == 0 /* Test recursive locks. */
1929+ && pthread_mutex_unlock (mutex) == 0
1930+ && pthread_mutex_unlock (mutex) == 0
1931+ && pthread_mutex_unlock (mutex) == 0
1932+ && pthread_mutex_destroy (mutex) == 0)
1933+ result = PASS;
1934+
1935+ return result;
1936+}
1937diff --git a/nptl/test-mutex-printers.py b/nptl/test-mutex-printers.py
1938new file mode 100644
1939index 0000000..7f542ad
1940--- /dev/null
1941+++ b/nptl/test-mutex-printers.py
1942@@ -0,0 +1,97 @@
1943+# Tests for the MutexPrinter class.
1944+#
1945+# Copyright (C) 2016 Free Software Foundation, Inc.
1946+# This file is part of the GNU C Library.
1947+#
1948+# The GNU C Library is free software; you can redistribute it and/or
1949+# modify it under the terms of the GNU Lesser General Public
1950+# License as published by the Free Software Foundation; either
1951+# version 2.1 of the License, or (at your option) any later version.
1952+#
1953+# The GNU C Library is distributed in the hope that it will be useful,
1954+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1955+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1956+# Lesser General Public License for more details.
1957+#
1958+# You should have received a copy of the GNU Lesser General Public
1959+# License along with the GNU C Library; if not, see
1960+# <http://www.gnu.org/licenses/>.
1961+
1962+import sys
1963+
1964+from test_printers_common import *
1965+
1966+test_source = sys.argv[1]
1967+test_bin = sys.argv[2]
1968+printer_files = sys.argv[3:]
1969+printer_names = ['global glibc-pthread-locks']
1970+
1971+try:
1972+ init_test(test_bin, printer_files, printer_names)
1973+ go_to_main()
1974+
1975+ var = 'mutex'
1976+ to_string = 'pthread_mutex_t'
1977+
1978+ break_at(test_source, 'Test status (destroyed)')
1979+ continue_cmd() # Go to test_status_destroyed
1980+ test_printer(var, to_string, {'Status': 'Destroyed'})
1981+
1982+ break_at(test_source, 'Test status (non-robust)')
1983+ continue_cmd() # Go to test_status_no_robust
1984+ test_printer(var, to_string, {'Status': 'Unlocked'})
1985+ next_cmd()
1986+ thread_id = get_current_thread_lwpid()
1987+ test_printer(var, to_string, {'Status': 'Locked, possibly with no waiters',
1988+ 'Owner ID': thread_id})
1989+
1990+ break_at(test_source, 'Test status (robust)')
1991+ continue_cmd() # Go to test_status_robust
1992+ test_printer(var, to_string, {'Status': 'Unlocked'})
1993+
1994+ # We'll now test the robust mutex locking states. We'll create a new
1995+ # thread that will lock a robust mutex and exit without unlocking it.
1996+ break_at(test_source, 'Create')
1997+ continue_cmd() # Go to test_locking_state_robust
1998+ # Set a breakpoint for the new thread to hit.
1999+ break_at(test_source, 'Thread function')
2000+ continue_cmd()
2001+ # By now the new thread is created and has hit its breakpoint.
2002+ set_scheduler_locking(True)
2003+ parent = 1
2004+ child = 2
2005+ select_thread(child)
2006+ child_id = get_current_thread_lwpid()
2007+ # We've got the new thread's ID.
2008+ select_thread(parent)
2009+ # Make the new thread finish its function while we wait.
2010+ continue_cmd(thread=child)
2011+ # The new thread should be dead by now.
2012+ break_at(test_source, 'Test locking (robust)')
2013+ continue_cmd()
2014+ test_printer(var, to_string, {'Owner ID': r'{0} \(dead\)'.format(child_id)})
2015+ # Try to lock and unlock the mutex.
2016+ next_cmd()
2017+ test_printer(var, to_string, {'Owner ID': thread_id,
2018+ 'State protected by this mutex': 'Inconsistent'})
2019+ next_cmd()
2020+ test_printer(var, to_string, {'Status': 'Unlocked',
2021+ 'State protected by this mutex': 'Not recoverable'})
2022+ set_scheduler_locking(False)
2023+
2024+ break_at(test_source, 'Test recursive locks')
2025+ continue_cmd() # Go to test_recursive_locks
2026+ test_printer(var, to_string, {'Times locked recursively': '2'})
2027+ next_cmd()
2028+ test_printer(var, to_string, {'Times locked recursively': '3'})
2029+ continue_cmd() # Exit
2030+
2031+except (NoLineError, pexpect.TIMEOUT) as exception:
2032+ print('Error: {0}'.format(exception))
2033+ result = FAIL
2034+
2035+else:
2036+ print('Test succeeded.')
2037+ result = PASS
2038+
2039+exit(result)
2040diff --git a/nptl/test-mutexattr-printers.c b/nptl/test-mutexattr-printers.c
2041new file mode 100644
2042index 0000000..9ecfff7
2043--- /dev/null
2044+++ b/nptl/test-mutexattr-printers.c
2045@@ -0,0 +1,144 @@
2046+/* Helper program for testing the pthread_mutex_t and pthread_mutexattr_t
2047+ pretty printers.
2048+
2049+ Copyright (C) 2016 Free Software Foundation, Inc.
2050+ This file is part of the GNU C Library.
2051+
2052+ The GNU C Library is free software; you can redistribute it and/or
2053+ modify it under the terms of the GNU Lesser General Public
2054+ License as published by the Free Software Foundation; either
2055+ version 2.1 of the License, or (at your option) any later version.
2056+
2057+ The GNU C Library is distributed in the hope that it will be useful,
2058+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2059+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2060+ Lesser General Public License for more details.
2061+
2062+ You should have received a copy of the GNU Lesser General Public
2063+ License along with the GNU C Library; if not, see
2064+ <http://www.gnu.org/licenses/>. */
2065+
2066+/* Keep the calls to the pthread_* functions on separate lines to make it easy
2067+ to advance through the program using the gdb 'next' command. */
2068+
2069+#include <pthread.h>
2070+
2071+#define PASS 0
2072+#define FAIL 1
2073+#define PRIOCEILING 42
2074+
2075+/* Need these so we don't have lines longer than 79 chars. */
2076+#define SET_TYPE(attr, type) pthread_mutexattr_settype (attr, type)
2077+#define SET_ROBUST(attr, robust) pthread_mutexattr_setrobust (attr, robust)
2078+#define SET_SHARED(attr, shared) pthread_mutexattr_setpshared (attr, shared)
2079+#define SET_PROTOCOL(attr, protocol) \
2080+ pthread_mutexattr_setprotocol (attr, protocol)
2081+#define SET_PRIOCEILING(mutex, prioceiling, old_ceiling) \
2082+ pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
2083+
2084+static int mutex_reinit (pthread_mutex_t *mutex,
2085+ const pthread_mutexattr_t *attr);
2086+static int test_settype (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
2087+static int test_setrobust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
2088+static int test_setpshared (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
2089+static int test_setprotocol (pthread_mutex_t *mutex,
2090+ pthread_mutexattr_t *attr);
2091+
2092+int
2093+main (void)
2094+{
2095+ pthread_mutex_t mutex;
2096+ pthread_mutexattr_t attr;
2097+ int result = FAIL;
2098+
2099+ if (pthread_mutexattr_init (&attr) == 0
2100+ && pthread_mutex_init (&mutex, NULL) == 0
2101+ && test_settype (&mutex, &attr) == PASS
2102+ && test_setrobust (&mutex, &attr) == PASS
2103+ && test_setpshared (&mutex, &attr) == PASS
2104+ && test_setprotocol (&mutex, &attr) == PASS)
2105+ result = PASS;
2106+ /* Else, one of the pthread_mutex* functions failed. */
2107+
2108+ return result;
2109+}
2110+
2111+/* Destroys MUTEX and re-initializes it using ATTR. */
2112+static int
2113+mutex_reinit (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
2114+{
2115+ int result = FAIL;
2116+
2117+ if (pthread_mutex_destroy (mutex) == 0
2118+ && pthread_mutex_init (mutex, attr) == 0)
2119+ result = PASS;
2120+
2121+ return result;
2122+}
2123+
2124+/* Tests setting the mutex type. */
2125+static int
2126+test_settype (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
2127+{
2128+ int result = FAIL;
2129+
2130+ if (SET_TYPE (attr, PTHREAD_MUTEX_ERRORCHECK) == 0 /* Set type. */
2131+ && mutex_reinit (mutex, attr) == 0
2132+ && SET_TYPE (attr, PTHREAD_MUTEX_RECURSIVE) == 0
2133+ && mutex_reinit (mutex, attr) == 0
2134+ && SET_TYPE (attr, PTHREAD_MUTEX_NORMAL) == 0
2135+ && mutex_reinit (mutex, attr) == 0)
2136+ result = PASS;
2137+
2138+ return result;
2139+}
2140+
2141+/* Tests setting whether the mutex is robust. */
2142+static int
2143+test_setrobust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
2144+{
2145+ int result = FAIL;
2146+
2147+ if (SET_ROBUST (attr, PTHREAD_MUTEX_ROBUST) == 0 /* Set robust. */
2148+ && mutex_reinit (mutex, attr) == 0
2149+ && SET_ROBUST (attr, PTHREAD_MUTEX_STALLED) == 0
2150+ && mutex_reinit (mutex, attr) == 0)
2151+ result = PASS;
2152+
2153+ return result;
2154+}
2155+
2156+/* Tests setting whether the mutex can be shared between processes. */
2157+static int
2158+test_setpshared (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
2159+{
2160+ int result = FAIL;
2161+
2162+ if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared. */
2163+ && mutex_reinit (mutex, attr) == 0
2164+ && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
2165+ && mutex_reinit (mutex, attr) == 0)
2166+ result = PASS;
2167+
2168+ return result;
2169+}
2170+
2171+/* Tests setting the mutex protocol and, for Priority Protect, the Priority
2172+ Ceiling. */
2173+static int
2174+test_setprotocol (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
2175+{
2176+ int result = FAIL;
2177+ int old_prioceiling;
2178+
2179+ if (SET_PROTOCOL (attr, PTHREAD_PRIO_INHERIT) == 0 /* Set protocol. */
2180+ && mutex_reinit (mutex, attr) == 0
2181+ && SET_PROTOCOL (attr, PTHREAD_PRIO_PROTECT) == 0
2182+ && mutex_reinit (mutex, attr) == 0
2183+ && SET_PRIOCEILING(mutex, PRIOCEILING, &old_prioceiling) == 0
2184+ && SET_PROTOCOL (attr, PTHREAD_PRIO_NONE) == 0
2185+ && mutex_reinit (mutex, attr) == 0)
2186+ result = PASS;
2187+
2188+ return result;
2189+}
2190diff --git a/nptl/test-mutexattr-printers.py b/nptl/test-mutexattr-printers.py
2191new file mode 100644
2192index 0000000..4464723
2193--- /dev/null
2194+++ b/nptl/test-mutexattr-printers.py
2195@@ -0,0 +1,101 @@
2196+# Common tests for the MutexPrinter and MutexAttributesPrinter classes.
2197+#
2198+# Copyright (C) 2016 Free Software Foundation, Inc.
2199+# This file is part of the GNU C Library.
2200+#
2201+# The GNU C Library is free software; you can redistribute it and/or
2202+# modify it under the terms of the GNU Lesser General Public
2203+# License as published by the Free Software Foundation; either
2204+# version 2.1 of the License, or (at your option) any later version.
2205+#
2206+# The GNU C Library is distributed in the hope that it will be useful,
2207+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2208+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2209+# Lesser General Public License for more details.
2210+#
2211+# You should have received a copy of the GNU Lesser General Public
2212+# License along with the GNU C Library; if not, see
2213+# <http://www.gnu.org/licenses/>.
2214+
2215+import sys
2216+
2217+from test_printers_common import *
2218+
2219+test_source = sys.argv[1]
2220+test_bin = sys.argv[2]
2221+printer_files = sys.argv[3:]
2222+printer_names = ['global glibc-pthread-locks']
2223+PRIOCEILING = 42
2224+
2225+try:
2226+ init_test(test_bin, printer_files, printer_names)
2227+ go_to_main()
2228+
2229+ check_debug_symbol('struct pthread_mutexattr')
2230+
2231+ mutex_var = 'mutex'
2232+ mutex_to_string = 'pthread_mutex_t'
2233+
2234+ attr_var = 'attr'
2235+ attr_to_string = 'pthread_mutexattr_t'
2236+
2237+ break_at(test_source, 'Set type')
2238+ continue_cmd() # Go to test_settype
2239+ next_cmd(2)
2240+ test_printer(attr_var, attr_to_string, {'Type': 'Error check'})
2241+ test_printer(mutex_var, mutex_to_string, {'Type': 'Error check'})
2242+ next_cmd(2)
2243+ test_printer(attr_var, attr_to_string, {'Type': 'Recursive'})
2244+ test_printer(mutex_var, mutex_to_string, {'Type': 'Recursive'})
2245+ next_cmd(2)
2246+ test_printer(attr_var, attr_to_string, {'Type': 'Normal'})
2247+ test_printer(mutex_var, mutex_to_string, {'Type': 'Normal'})
2248+
2249+ break_at(test_source, 'Set robust')
2250+ continue_cmd() # Go to test_setrobust
2251+ next_cmd(2)
2252+ test_printer(attr_var, attr_to_string, {'Robust': 'Yes'})
2253+ test_printer(mutex_var, mutex_to_string, {'Robust': 'Yes'})
2254+ next_cmd(2)
2255+ test_printer(attr_var, attr_to_string, {'Robust': 'No'})
2256+ test_printer(mutex_var, mutex_to_string, {'Robust': 'No'})
2257+
2258+ break_at(test_source, 'Set shared')
2259+ continue_cmd() # Go to test_setpshared
2260+ next_cmd(2)
2261+ test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
2262+ test_printer(mutex_var, mutex_to_string, {'Shared': 'Yes'})
2263+ next_cmd(2)
2264+ test_printer(attr_var, attr_to_string, {'Shared': 'No'})
2265+ test_printer(mutex_var, mutex_to_string, {'Shared': 'No'})
2266+
2267+ break_at(test_source, 'Set protocol')
2268+ continue_cmd() # Go to test_setprotocol
2269+ next_cmd(2)
2270+ test_printer(attr_var, attr_to_string, {'Protocol': 'Priority inherit'})
2271+ test_printer(mutex_var, mutex_to_string, {'Protocol': 'Priority inherit'})
2272+ next_cmd(2)
2273+ test_printer(attr_var, attr_to_string, {'Protocol': 'Priority protect'})
2274+ test_printer(mutex_var, mutex_to_string, {'Protocol': 'Priority protect'})
2275+ next_cmd(2)
2276+ test_printer(mutex_var, mutex_to_string, {'Priority ceiling':
2277+ str(PRIOCEILING)})
2278+ next_cmd()
2279+ test_printer(attr_var, attr_to_string, {'Protocol': 'None'})
2280+ test_printer(mutex_var, mutex_to_string, {'Protocol': 'None'})
2281+
2282+ continue_cmd() # Exit
2283+
2284+except (NoLineError, pexpect.TIMEOUT) as exception:
2285+ print('Error: {0}'.format(exception))
2286+ result = FAIL
2287+
2288+except DebugError as exception:
2289+ print(exception)
2290+ result = UNSUPPORTED
2291+
2292+else:
2293+ print('Test succeeded.')
2294+ result = PASS
2295+
2296+exit(result)
2297diff --git a/nptl/test-rwlock-printers.c b/nptl/test-rwlock-printers.c
2298new file mode 100644
2299index 0000000..dbbe9b8
2300--- /dev/null
2301+++ b/nptl/test-rwlock-printers.c
2302@@ -0,0 +1,78 @@
2303+/* Helper program for testing the pthread_rwlock_t pretty printer.
2304+
2305+ Copyright (C) 2016 Free Software Foundation, Inc.
2306+ This file is part of the GNU C Library.
2307+
2308+ The GNU C Library is free software; you can redistribute it and/or
2309+ modify it under the terms of the GNU Lesser General Public
2310+ License as published by the Free Software Foundation; either
2311+ version 2.1 of the License, or (at your option) any later version.
2312+
2313+ The GNU C Library is distributed in the hope that it will be useful,
2314+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2315+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2316+ Lesser General Public License for more details.
2317+
2318+ You should have received a copy of the GNU Lesser General Public
2319+ License along with the GNU C Library; if not, see
2320+ <http://www.gnu.org/licenses/>. */
2321+
2322+/* Keep the calls to the pthread_* functions on separate lines to make it easy
2323+ to advance through the program using the gdb 'next' command. */
2324+
2325+#include <pthread.h>
2326+
2327+#define PASS 0
2328+#define FAIL 1
2329+
2330+static int test_locking_reader (pthread_rwlock_t *rwlock);
2331+static int test_locking_writer (pthread_rwlock_t *rwlock);
2332+
2333+int
2334+main (void)
2335+{
2336+ pthread_rwlock_t rwlock;
2337+
2338+ int result = FAIL;
2339+
2340+ if (test_locking_reader (&rwlock) == PASS
2341+ && test_locking_writer (&rwlock) == PASS)
2342+ result = PASS;
2343+ /* Else, one of the pthread_rwlock* functions failed. */
2344+
2345+ return result;
2346+}
2347+
2348+/* Tests locking the rwlock multiple times as a reader. */
2349+static int
2350+test_locking_reader (pthread_rwlock_t *rwlock)
2351+{
2352+ int result = FAIL;
2353+
2354+ if (pthread_rwlock_init (rwlock, NULL) == 0
2355+ && pthread_rwlock_rdlock (rwlock) == 0 /* Test locking (reader). */
2356+ && pthread_rwlock_rdlock (rwlock) == 0
2357+ && pthread_rwlock_rdlock (rwlock) == 0
2358+ && pthread_rwlock_unlock (rwlock) == 0
2359+ && pthread_rwlock_unlock (rwlock) == 0
2360+ && pthread_rwlock_unlock (rwlock) == 0
2361+ && pthread_rwlock_destroy (rwlock) == 0)
2362+ result = PASS;
2363+
2364+ return result;
2365+}
2366+
2367+/* Tests locking the rwlock as a writer. */
2368+static int
2369+test_locking_writer (pthread_rwlock_t *rwlock)
2370+{
2371+ int result = FAIL;
2372+
2373+ if (pthread_rwlock_init (rwlock, NULL) == 0
2374+ && pthread_rwlock_wrlock (rwlock) == 0 /* Test locking (writer). */
2375+ && pthread_rwlock_unlock (rwlock) == 0
2376+ && pthread_rwlock_destroy (rwlock) == 0)
2377+ result = PASS;
2378+
2379+ return result;
2380+}
2381diff --git a/nptl/test-rwlock-printers.py b/nptl/test-rwlock-printers.py
2382new file mode 100644
2383index 0000000..b972fa6
2384--- /dev/null
2385+++ b/nptl/test-rwlock-printers.py
2386@@ -0,0 +1,64 @@
2387+# Common tests for the RWLockPrinter class.
2388+#
2389+# Copyright (C) 2016 Free Software Foundation, Inc.
2390+# This file is part of the GNU C Library.
2391+#
2392+# The GNU C Library is free software; you can redistribute it and/or
2393+# modify it under the terms of the GNU Lesser General Public
2394+# License as published by the Free Software Foundation; either
2395+# version 2.1 of the License, or (at your option) any later version.
2396+#
2397+# The GNU C Library is distributed in the hope that it will be useful,
2398+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2399+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2400+# Lesser General Public License for more details.
2401+#
2402+# You should have received a copy of the GNU Lesser General Public
2403+# License along with the GNU C Library; if not, see
2404+# <http://www.gnu.org/licenses/>.
2405+
2406+import sys
2407+
2408+from test_printers_common import *
2409+
2410+test_source = sys.argv[1]
2411+test_bin = sys.argv[2]
2412+printer_files = sys.argv[3:]
2413+printer_names = ['global glibc-pthread-locks']
2414+
2415+try:
2416+ init_test(test_bin, printer_files, printer_names)
2417+ go_to_main()
2418+
2419+ var = 'rwlock'
2420+ to_string = 'pthread_rwlock_t'
2421+
2422+ break_at(test_source, 'Test locking (reader)')
2423+ continue_cmd() # Go to test_locking_reader
2424+ test_printer(var, to_string, {'Status': 'Unlocked'})
2425+ next_cmd()
2426+ test_printer(var, to_string, {'Status': r'Locked \(Read\)', 'Readers': '1'})
2427+ next_cmd()
2428+ test_printer(var, to_string, {'Readers': '2'})
2429+ next_cmd()
2430+ test_printer(var, to_string, {'Readers': '3'})
2431+
2432+ break_at(test_source, 'Test locking (writer)')
2433+ continue_cmd() # Go to test_locking_writer
2434+ test_printer(var, to_string, {'Status': 'Unlocked'})
2435+ next_cmd()
2436+ thread_id = get_current_thread_lwpid()
2437+ test_printer(var, to_string, {'Status': r'Locked \(Write\)',
2438+ 'Writer ID': thread_id})
2439+
2440+ continue_cmd() # Exit
2441+
2442+except (NoLineError, pexpect.TIMEOUT) as exception:
2443+ print('Error: {0}'.format(exception))
2444+ result = FAIL
2445+
2446+else:
2447+ print('Test succeeded.')
2448+ result = PASS
2449+
2450+exit(result)
2451diff --git a/nptl/test-rwlockattr-printers.c b/nptl/test-rwlockattr-printers.c
2452new file mode 100644
2453index 0000000..d12facf
2454--- /dev/null
2455+++ b/nptl/test-rwlockattr-printers.c
2456@@ -0,0 +1,98 @@
2457+/* Helper program for testing the pthread_rwlock_t and pthread_rwlockattr_t
2458+ pretty printers.
2459+
2460+ Copyright (C) 2016 Free Software Foundation, Inc.
2461+ This file is part of the GNU C Library.
2462+
2463+ The GNU C Library is free software; you can redistribute it and/or
2464+ modify it under the terms of the GNU Lesser General Public
2465+ License as published by the Free Software Foundation; either
2466+ version 2.1 of the License, or (at your option) any later version.
2467+
2468+ The GNU C Library is distributed in the hope that it will be useful,
2469+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2470+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2471+ Lesser General Public License for more details.
2472+
2473+ You should have received a copy of the GNU Lesser General Public
2474+ License along with the GNU C Library; if not, see
2475+ <http://www.gnu.org/licenses/>. */
2476+
2477+/* Keep the calls to the pthread_* functions on separate lines to make it easy
2478+ to advance through the program using the gdb 'next' command. */
2479+
2480+#include <pthread.h>
2481+
2482+#define PASS 0
2483+#define FAIL 1
2484+
2485+/* Need these so we don't have lines longer than 79 chars. */
2486+#define SET_KIND(attr, kind) pthread_rwlockattr_setkind_np (attr, kind)
2487+#define SET_SHARED(attr, shared) pthread_rwlockattr_setpshared (attr, shared)
2488+
2489+static int rwlock_reinit (pthread_rwlock_t *rwlock,
2490+ const pthread_rwlockattr_t *attr);
2491+static int test_setkind_np (pthread_rwlock_t *rwlock,
2492+ pthread_rwlockattr_t *attr);
2493+static int test_setpshared (pthread_rwlock_t *rwlock,
2494+ pthread_rwlockattr_t *attr);
2495+
2496+int
2497+main (void)
2498+{
2499+ pthread_rwlock_t rwlock;
2500+ pthread_rwlockattr_t attr;
2501+ int result = FAIL;
2502+
2503+ if (pthread_rwlockattr_init (&attr) == 0
2504+ && pthread_rwlock_init (&rwlock, NULL) == 0
2505+ && test_setkind_np (&rwlock, &attr) == PASS
2506+ && test_setpshared (&rwlock, &attr) == PASS)
2507+ result = PASS;
2508+ /* Else, one of the pthread_rwlock* functions failed. */
2509+
2510+ return result;
2511+}
2512+
2513+/* Destroys RWLOCK and re-initializes it using ATTR. */
2514+static int
2515+rwlock_reinit (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
2516+{
2517+ int result = FAIL;
2518+
2519+ if (pthread_rwlock_destroy (rwlock) == 0
2520+ && pthread_rwlock_init (rwlock, attr) == 0)
2521+ result = PASS;
2522+
2523+ return result;
2524+}
2525+
2526+/* Tests setting whether the rwlock prefers readers or writers. */
2527+static int
2528+test_setkind_np (pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr)
2529+{
2530+ int result = FAIL;
2531+
2532+ if (SET_KIND (attr, PTHREAD_RWLOCK_PREFER_READER_NP) == 0 /* Set kind. */
2533+ && rwlock_reinit (rwlock, attr) == PASS
2534+ && SET_KIND (attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) == 0
2535+ && rwlock_reinit (rwlock, attr) == PASS)
2536+ result = PASS;
2537+
2538+ return result;
2539+}
2540+
2541+/* Tests setting whether the rwlock can be shared between processes. */
2542+static int
2543+test_setpshared (pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr)
2544+{
2545+ int result = FAIL;
2546+
2547+ if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared. */
2548+ && rwlock_reinit (rwlock, attr) == PASS
2549+ && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
2550+ && rwlock_reinit (rwlock, attr) == PASS)
2551+ result = PASS;
2552+
2553+ return result;
2554+}
2555diff --git a/nptl/test-rwlockattr-printers.py b/nptl/test-rwlockattr-printers.py
2556new file mode 100644
2557index 0000000..1ca2dc6
2558--- /dev/null
2559+++ b/nptl/test-rwlockattr-printers.py
2560@@ -0,0 +1,73 @@
2561+# Common tests for the RWLockPrinter and RWLockAttributesPrinter classes.
2562+#
2563+# Copyright (C) 2016 Free Software Foundation, Inc.
2564+# This file is part of the GNU C Library.
2565+#
2566+# The GNU C Library is free software; you can redistribute it and/or
2567+# modify it under the terms of the GNU Lesser General Public
2568+# License as published by the Free Software Foundation; either
2569+# version 2.1 of the License, or (at your option) any later version.
2570+#
2571+# The GNU C Library is distributed in the hope that it will be useful,
2572+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2573+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2574+# Lesser General Public License for more details.
2575+#
2576+# You should have received a copy of the GNU Lesser General Public
2577+# License along with the GNU C Library; if not, see
2578+# <http://www.gnu.org/licenses/>.
2579+
2580+import sys
2581+
2582+from test_printers_common import *
2583+
2584+test_source = sys.argv[1]
2585+test_bin = sys.argv[2]
2586+printer_files = sys.argv[3:]
2587+printer_names = ['global glibc-pthread-locks']
2588+
2589+try:
2590+ init_test(test_bin, printer_files, printer_names)
2591+ go_to_main()
2592+
2593+ check_debug_symbol('struct pthread_rwlockattr')
2594+
2595+ rwlock_var = 'rwlock'
2596+ rwlock_to_string = 'pthread_rwlock_t'
2597+
2598+ attr_var = 'attr'
2599+ attr_to_string = 'pthread_rwlockattr_t'
2600+
2601+ break_at(test_source, 'Set kind')
2602+ continue_cmd() # Go to test_setkind_np
2603+ next_cmd(2)
2604+ test_printer(rwlock_var, rwlock_to_string, {'Prefers': 'Readers'})
2605+ test_printer(attr_var, attr_to_string, {'Prefers': 'Readers'})
2606+ next_cmd(2)
2607+ test_printer(rwlock_var, rwlock_to_string, {'Prefers': 'Writers'})
2608+ test_printer(attr_var, attr_to_string, {'Prefers': 'Writers'})
2609+
2610+ break_at(test_source, 'Set shared')
2611+ continue_cmd() # Go to test_setpshared
2612+ next_cmd(2)
2613+ test_printer(rwlock_var, rwlock_to_string, {'Shared': 'Yes'})
2614+ test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
2615+ next_cmd(2)
2616+ test_printer(rwlock_var, rwlock_to_string, {'Shared': 'No'})
2617+ test_printer(attr_var, attr_to_string, {'Shared': 'No'})
2618+
2619+ continue_cmd() # Exit
2620+
2621+except (NoLineError, pexpect.TIMEOUT) as exception:
2622+ print('Error: {0}'.format(exception))
2623+ result = FAIL
2624+
2625+except DebugError as exception:
2626+ print(exception)
2627+ result = UNSUPPORTED
2628+
2629+else:
2630+ print('Test succeeded.')
2631+ result = PASS
2632+
2633+exit(result)
2634diff --git a/scripts/gen-py-const.awk b/scripts/gen-py-const.awk
2635new file mode 100644
2636index 0000000..4586f59
2637--- /dev/null
2638+++ b/scripts/gen-py-const.awk
2639@@ -0,0 +1,118 @@
2640+# Script to generate constants for Python pretty printers.
2641+#
2642+# Copyright (C) 2016 Free Software Foundation, Inc.
2643+# This file is part of the GNU C Library.
2644+#
2645+# The GNU C Library is free software; you can redistribute it and/or
2646+# modify it under the terms of the GNU Lesser General Public
2647+# License as published by the Free Software Foundation; either
2648+# version 2.1 of the License, or (at your option) any later version.
2649+#
2650+# The GNU C Library is distributed in the hope that it will be useful,
2651+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2652+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2653+# Lesser General Public License for more details.
2654+#
2655+# You should have received a copy of the GNU Lesser General Public
2656+# License along with the GNU C Library; if not, see
2657+# <http://www.gnu.org/licenses/>.
2658+
2659+# This script is a smaller version of the clever gen-asm-const.awk hack used to
2660+# generate ASM constants from .sym files. We'll use this to generate constants
2661+# for Python pretty printers.
2662+#
2663+# The input to this script are .pysym files that look like:
2664+# #C_Preprocessor_Directive...
2665+# NAME1
2666+# NAME2 expression...
2667+#
2668+# A line giving just a name implies an expression consisting of just that name.
2669+# Comments start with '--'.
2670+#
2671+# The output of this script is a 'dummy' function containing 'asm' declarations
2672+# for each non-preprocessor line in the .pysym file. The expression values
2673+# will appear as input operands to the 'asm' declaration. For example, if we
2674+# have:
2675+#
2676+# /* header.h */
2677+# #define MACRO 42
2678+#
2679+# struct S {
2680+# char c1;
2681+# char c2;
2682+# char c3;
2683+# };
2684+#
2685+# enum E {
2686+# ZERO,
2687+# ONE
2688+# };
2689+#
2690+# /* symbols.pysym */
2691+# #include <stddef.h>
2692+# #include "header.h"
2693+# -- This is a comment
2694+# MACRO
2695+# C3_OFFSET offsetof(struct S, c3)
2696+# E_ONE ONE
2697+#
2698+# the output will be:
2699+#
2700+# #include <stddef.h>
2701+# #include "header.h"
2702+# void dummy(void)
2703+# {
2704+# asm ("@name@MACRO@value@%0@" : : "i" (MACRO));
2705+# asm ("@name@C3_OFFSET@value@%0@" : : "i" (offsetof(struct S, c3)));
2706+# asm ("@name@E_ONE@value@%0@" : : "i" (ONE));
2707+# }
2708+#
2709+# We'll later feed this output to gcc -S. Since '-S' tells gcc to compile but
2710+# not assemble, gcc will output something like:
2711+#
2712+# dummy:
2713+# ...
2714+# @name@MACRO@value@$42@
2715+# @name@C3_OFFSET@value@$2@
2716+# @name@E_ONE@value@$1@
2717+#
2718+# Finally, we can process that output to extract the constant values.
2719+# Notice gcc may prepend a special character such as '$' to each value.
2720+
2721+# found_symbol indicates whether we found a non-comment, non-preprocessor line.
2722+BEGIN { found_symbol = 0 }
2723+
2724+# C preprocessor directives go straight through.
2725+/^#/ { print; next; }
2726+
2727+# Skip comments.
2728+/--/ { next; }
2729+
2730+# Trim leading whitespace.
2731+{ sub(/^[[:blank:]]*/, ""); }
2732+
2733+# If we found a non-comment, non-preprocessor line, print the 'dummy' function
2734+# header.
2735+NF > 0 && !found_symbol {
2736+ print "void dummy(void)\n{";
2737+ found_symbol = 1;
2738+}
2739+
2740+# If the line contains just a name, duplicate it so we can use that name
2741+# as the value of the expression.
2742+NF == 1 { sub(/^.*$/, "& &"); }
2743+
2744+# If a line contains a name and an expression...
2745+NF > 1 {
2746+ name = $1;
2747+
2748+ # Remove any characters before the second field.
2749+ sub(/^[^[:blank:]]+[[:blank:]]+/, "");
2750+
2751+ # '$0' ends up being everything that appeared after the first field
2752+ # separator.
2753+ printf " asm (\"@name@%s@value@%0@\" : : \"i\" (%s));\n", name, $0;
2754+}
2755+
2756+# Close the 'dummy' function.
2757+END { if (found_symbol) print "}"; }
2758diff --git a/scripts/test_printers_common.py b/scripts/test_printers_common.py
2759new file mode 100644
2760index 0000000..c79d7e3
2761--- /dev/null
2762+++ b/scripts/test_printers_common.py
2763@@ -0,0 +1,364 @@
2764+# Common functions and variables for testing the Python pretty printers.
2765+#
2766+# Copyright (C) 2016 Free Software Foundation, Inc.
2767+# This file is part of the GNU C Library.
2768+#
2769+# The GNU C Library is free software; you can redistribute it and/or
2770+# modify it under the terms of the GNU Lesser General Public
2771+# License as published by the Free Software Foundation; either
2772+# version 2.1 of the License, or (at your option) any later version.
2773+#
2774+# The GNU C Library is distributed in the hope that it will be useful,
2775+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2776+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2777+# Lesser General Public License for more details.
2778+#
2779+# You should have received a copy of the GNU Lesser General Public
2780+# License along with the GNU C Library; if not, see
2781+# <http://www.gnu.org/licenses/>.
2782+
2783+"""These tests require PExpect 4.0 or newer.
2784+
2785+Exported constants:
2786+ PASS, FAIL, UNSUPPORTED (int): Test exit codes, as per evaluate-test.sh.
2787+"""
2788+
2789+import os
2790+import re
2791+from test_printers_exceptions import *
2792+
2793+PASS = 0
2794+FAIL = 1
2795+UNSUPPORTED = 77
2796+
2797+gdb_bin = 'gdb'
2798+gdb_options = '-q -nx'
2799+gdb_invocation = '{0} {1}'.format(gdb_bin, gdb_options)
2800+pexpect_min_version = 4
2801+gdb_min_version = (7, 8)
2802+encoding = 'utf-8'
2803+
2804+try:
2805+ import pexpect
2806+except ImportError:
2807+ print('PExpect 4.0 or newer must be installed to test the pretty printers.')
2808+ exit(UNSUPPORTED)
2809+
2810+pexpect_version = pexpect.__version__.split('.')[0]
2811+
2812+if int(pexpect_version) < pexpect_min_version:
2813+ print('PExpect 4.0 or newer must be installed to test the pretty printers.')
2814+ exit(UNSUPPORTED)
2815+
2816+if not pexpect.which(gdb_bin):
2817+ print('gdb 7.8 or newer must be installed to test the pretty printers.')
2818+ exit(UNSUPPORTED)
2819+
2820+timeout = 5
2821+TIMEOUTFACTOR = os.environ.get('TIMEOUTFACTOR')
2822+
2823+if TIMEOUTFACTOR:
2824+ timeout = int(TIMEOUTFACTOR)
2825+
2826+try:
2827+ # Check the gdb version.
2828+ version_cmd = '{0} --version'.format(gdb_invocation, timeout=timeout)
2829+ gdb_version_out = pexpect.run(version_cmd, encoding=encoding)
2830+
2831+ # The gdb version string is "GNU gdb <PKGVERSION><version>", where
2832+ # PKGVERSION can be any text. We assume that there'll always be a space
2833+ # between PKGVERSION and the version number for the sake of the regexp.
2834+ version_match = re.search(r'GNU gdb .* ([1-9]+)\.([0-9]+)', gdb_version_out)
2835+
2836+ if not version_match:
2837+ print('The gdb version string (gdb -v) is incorrectly formatted.')
2838+ exit(UNSUPPORTED)
2839+
2840+ gdb_version = (int(version_match.group(1)), int(version_match.group(2)))
2841+
2842+ if gdb_version < gdb_min_version:
2843+ print('gdb 7.8 or newer must be installed to test the pretty printers.')
2844+ exit(UNSUPPORTED)
2845+
2846+ # Check if gdb supports Python.
2847+ gdb_python_cmd = '{0} -ex "python import os" -batch'.format(gdb_invocation,
2848+ timeout=timeout)
2849+ gdb_python_error = pexpect.run(gdb_python_cmd, encoding=encoding)
2850+
2851+ if gdb_python_error:
2852+ print('gdb must have python support to test the pretty printers.')
2853+ exit(UNSUPPORTED)
2854+
2855+ # If everything's ok, spawn the gdb process we'll use for testing.
2856+ gdb = pexpect.spawn(gdb_invocation, echo=False, timeout=timeout,
2857+ encoding=encoding)
2858+ gdb_prompt = u'\(gdb\)'
2859+ gdb.expect(gdb_prompt)
2860+
2861+except pexpect.ExceptionPexpect as exception:
2862+ print('Error: {0}'.format(exception))
2863+ exit(FAIL)
2864+
2865+def test(command, pattern=None):
2866+ """Sends 'command' to gdb and expects the given 'pattern'.
2867+
2868+ If 'pattern' is None, simply consumes everything up to and including
2869+ the gdb prompt.
2870+
2871+ Args:
2872+ command (string): The command we'll send to gdb.
2873+ pattern (raw string): A pattern the gdb output should match.
2874+
2875+ Returns:
2876+ string: The string that matched 'pattern', or an empty string if
2877+ 'pattern' was None.
2878+ """
2879+
2880+ match = ''
2881+
2882+ gdb.sendline(command)
2883+
2884+ if pattern:
2885+ # PExpect does a non-greedy match for '+' and '*'. Since it can't look
2886+ # ahead on the gdb output stream, if 'pattern' ends with a '+' or a '*'
2887+ # we may end up matching only part of the required output.
2888+ # To avoid this, we'll consume 'pattern' and anything that follows it
2889+ # up to and including the gdb prompt, then extract 'pattern' later.
2890+ index = gdb.expect([u'{0}.+{1}'.format(pattern, gdb_prompt),
2891+ pexpect.TIMEOUT])
2892+
2893+ if index == 0:
2894+ # gdb.after now contains the whole match. Extract the text that
2895+ # matches 'pattern'.
2896+ match = re.match(pattern, gdb.after, re.DOTALL).group()
2897+ elif index == 1:
2898+ # We got a timeout exception. Print information on what caused it
2899+ # and bail out.
2900+ error = ('Response does not match the expected pattern.\n'
2901+ 'Command: {0}\n'
2902+ 'Expected pattern: {1}\n'
2903+ 'Response: {2}'.format(command, pattern, gdb.before))
2904+
2905+ raise pexpect.TIMEOUT(error)
2906+ else:
2907+ # Consume just the the gdb prompt.
2908+ gdb.expect(gdb_prompt)
2909+
2910+ return match
2911+
2912+def init_test(test_bin, printer_files, printer_names):
2913+ """Loads the test binary file and the required pretty printers to gdb.
2914+
2915+ Args:
2916+ test_bin (string): The name of the test binary file.
2917+ pretty_printers (list of strings): A list with the names of the pretty
2918+ printer files.
2919+ """
2920+
2921+ # Load all the pretty printer files. We're assuming these are safe.
2922+ for printer_file in printer_files:
2923+ test('source {0}'.format(printer_file))
2924+
2925+ # Disable all the pretty printers.
2926+ test('disable pretty-printer', r'0 of [0-9]+ printers enabled')
2927+
2928+ # Enable only the required printers.
2929+ for printer in printer_names:
2930+ test('enable pretty-printer {0}'.format(printer),
2931+ r'[1-9][0-9]* of [1-9]+ printers enabled')
2932+
2933+ # Finally, load the test binary.
2934+ test('file {0}'.format(test_bin))
2935+
2936+def go_to_main():
2937+ """Executes a gdb 'start' command, which takes us to main."""
2938+
2939+ test('start', r'main')
2940+
2941+def get_line_number(file_name, string):
2942+ """Returns the number of the line in which 'string' appears within a file.
2943+
2944+ Args:
2945+ file_name (string): The name of the file we'll search through.
2946+ string (string): The string we'll look for.
2947+
2948+ Returns:
2949+ int: The number of the line in which 'string' appears, starting from 1.
2950+ """
2951+ number = -1
2952+
2953+ with open(file_name) as src_file:
2954+ for i, line in enumerate(src_file):
2955+ if string in line:
2956+ number = i + 1
2957+ break
2958+
2959+ if number == -1:
2960+ raise NoLineError(file_name, string)
2961+
2962+ return number
2963+
2964+def break_at(file_name, string, temporary=True, thread=None):
2965+ """Places a breakpoint on the first line in 'file_name' containing 'string'.
2966+
2967+ 'string' is usually a comment like "Stop here". Notice this may fail unless
2968+ the comment is placed inline next to actual code, e.g.:
2969+
2970+ ...
2971+ /* Stop here */
2972+ ...
2973+
2974+ may fail, while:
2975+
2976+ ...
2977+ some_func(); /* Stop here */
2978+ ...
2979+
2980+ will succeed.
2981+
2982+ If 'thread' isn't None, the breakpoint will be set for all the threads.
2983+ Otherwise, it'll be set only for 'thread'.
2984+
2985+ Args:
2986+ file_name (string): The name of the file we'll place the breakpoint in.
2987+ string (string): A string we'll look for inside the file.
2988+ We'll place a breakpoint on the line which contains it.
2989+ temporary (bool): Whether the breakpoint should be automatically deleted
2990+ after we reach it.
2991+ thread (int): The number of the thread we'll place the breakpoint for,
2992+ as seen by gdb. If specified, it should be greater than zero.
2993+ """
2994+
2995+ if not thread:
2996+ thread_str = ''
2997+ else:
2998+ thread_str = 'thread {0}'.format(thread)
2999+
3000+ if temporary:
3001+ command = 'tbreak'
3002+ break_type = 'Temporary breakpoint'
3003+ else:
3004+ command = 'break'
3005+ break_type = 'Breakpoint'
3006+
3007+ line_number = str(get_line_number(file_name, string))
3008+
3009+ test('{0} {1}:{2} {3}'.format(command, file_name, line_number, thread_str),
3010+ r'{0} [0-9]+ at 0x[a-f0-9]+: file {1}, line {2}\.'.format(break_type,
3011+ file_name,
3012+ line_number))
3013+
3014+def continue_cmd(thread=None):
3015+ """Executes a gdb 'continue' command.
3016+
3017+ If 'thread' isn't None, the command will be applied to all the threads.
3018+ Otherwise, it'll be applied only to 'thread'.
3019+
3020+ Args:
3021+ thread (int): The number of the thread we'll apply the command to,
3022+ as seen by gdb. If specified, it should be greater than zero.
3023+ """
3024+
3025+ if not thread:
3026+ command = 'continue'
3027+ else:
3028+ command = 'thread apply {0} continue'.format(thread)
3029+
3030+ test(command)
3031+
3032+def next_cmd(count=1, thread=None):
3033+ """Executes a gdb 'next' command.
3034+
3035+ If 'thread' isn't None, the command will be applied to all the threads.
3036+ Otherwise, it'll be applied only to 'thread'.
3037+
3038+ Args:
3039+ count (int): The 'count' argument of the 'next' command.
3040+ thread (int): The number of the thread we'll apply the command to,
3041+ as seen by gdb. If specified, it should be greater than zero.
3042+ """
3043+
3044+ if not thread:
3045+ command = 'next'
3046+ else:
3047+ command = 'thread apply {0} next'
3048+
3049+ test('{0} {1}'.format(command, count))
3050+
3051+def select_thread(thread):
3052+ """Selects the thread indicated by 'thread'.
3053+
3054+ Args:
3055+ thread (int): The number of the thread we'll switch to, as seen by gdb.
3056+ This should be greater than zero.
3057+ """
3058+
3059+ if thread > 0:
3060+ test('thread {0}'.format(thread))
3061+
3062+def get_current_thread_lwpid():
3063+ """Gets the current thread's Lightweight Process ID.
3064+
3065+ Returns:
3066+ string: The current thread's LWP ID.
3067+ """
3068+
3069+ # It's easier to get the LWP ID through the Python API than the gdb CLI.
3070+ command = 'python print(gdb.selected_thread().ptid[1])'
3071+
3072+ return test(command, r'[0-9]+')
3073+
3074+def set_scheduler_locking(mode):
3075+ """Executes the gdb 'set scheduler-locking' command.
3076+
3077+ Args:
3078+ mode (bool): Whether the scheduler locking mode should be 'on'.
3079+ """
3080+ modes = {
3081+ True: 'on',
3082+ False: 'off'
3083+ }
3084+
3085+ test('set scheduler-locking {0}'.format(modes[mode]))
3086+
3087+def test_printer(var, to_string, children=None, is_ptr=True):
3088+ """ Tests the output of a pretty printer.
3089+
3090+ For a variable called 'var', this tests whether its associated printer
3091+ outputs the expected 'to_string' and children (if any).
3092+
3093+ Args:
3094+ var (string): The name of the variable we'll print.
3095+ to_string (raw string): The expected output of the printer's 'to_string'
3096+ method.
3097+ children (map {raw string->raw string}): A map with the expected output
3098+ of the printer's children' method.
3099+ is_ptr (bool): Whether 'var' is a pointer, and thus should be
3100+ dereferenced.
3101+ """
3102+
3103+ if is_ptr:
3104+ var = '*{0}'.format(var)
3105+
3106+ test('print {0}'.format(var), to_string)
3107+
3108+ if children:
3109+ for name, value in children.items():
3110+ # Children are shown as 'name = value'.
3111+ test('print {0}'.format(var), r'{0} = {1}'.format(name, value))
3112+
3113+def check_debug_symbol(symbol):
3114+ """ Tests whether a given debugging symbol exists.
3115+
3116+ If the symbol doesn't exist, raises a DebugError.
3117+
3118+ Args:
3119+ symbol (string): The symbol we're going to check for.
3120+ """
3121+
3122+ try:
3123+ test('ptype {0}'.format(symbol), r'type = {0}'.format(symbol))
3124+
3125+ except pexpect.TIMEOUT:
3126+ # The symbol doesn't exist.
3127+ raise DebugError(symbol)
3128diff --git a/scripts/test_printers_exceptions.py b/scripts/test_printers_exceptions.py
3129new file mode 100644
3130index 0000000..17034b5
3131--- /dev/null
3132+++ b/scripts/test_printers_exceptions.py
3133@@ -0,0 +1,61 @@
3134+# Exception classes used when testing the Python pretty printers.
3135+#
3136+# Copyright (C) 2016 Free Software Foundation, Inc.
3137+# This file is part of the GNU C Library.
3138+#
3139+# The GNU C Library is free software; you can redistribute it and/or
3140+# modify it under the terms of the GNU Lesser General Public
3141+# License as published by the Free Software Foundation; either
3142+# version 2.1 of the License, or (at your option) any later version.
3143+#
3144+# The GNU C Library is distributed in the hope that it will be useful,
3145+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3146+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3147+# Lesser General Public License for more details.
3148+#
3149+# You should have received a copy of the GNU Lesser General Public
3150+# License along with the GNU C Library; if not, see
3151+# <http://www.gnu.org/licenses/>.
3152+
3153+class NoLineError(Exception):
3154+ """Custom exception to indicate that a test file doesn't contain
3155+ the requested string.
3156+ """
3157+
3158+ def __init__(self, file_name, string):
3159+ """Constructor.
3160+
3161+ Args:
3162+ file_name (string): The name of the test file.
3163+ string (string): The string that was requested.
3164+ """
3165+
3166+ super(NoLineError, self).__init__()
3167+ self.file_name = file_name
3168+ self.string = string
3169+
3170+ def __str__(self):
3171+ """Shows a readable representation of the exception."""
3172+
3173+ return ('File {0} has no line containing the following string: {1}'
3174+ .format(self.file_name, self.string))
3175+
3176+class DebugError(Exception):
3177+ """Custom exception to indicate that a required debugging symbol is missing.
3178+ """
3179+
3180+ def __init__(self, symbol):
3181+ """Constructor.
3182+
3183+ Args:
3184+ symbol (string): The name of the entity whose debug info is missing.
3185+ """
3186+
3187+ super(DebugError, self).__init__()
3188+ self.symbol = symbol
3189+
3190+ def __str__(self):
3191+ """Shows a readable representation of the exception."""
3192+
3193+ return ('The required debugging information for {0} is missing.'
3194+ .format(self.symbol))
3195--
31962.10.2
3197