about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
Diffstat (limited to 'nptl')
-rw-r--r--nptl/Makefile18
-rw-r--r--nptl/nptl-printers.py633
-rw-r--r--nptl/nptl_lock_constants.pysym75
-rw-r--r--nptl/test-cond-printers.c57
-rw-r--r--nptl/test-cond-printers.py50
-rw-r--r--nptl/test-condattr-printers.c94
-rw-r--r--nptl/test-condattr-printers.py71
-rw-r--r--nptl/test-mutex-printers.c151
-rw-r--r--nptl/test-mutex-printers.py97
-rw-r--r--nptl/test-mutexattr-printers.c144
-rw-r--r--nptl/test-mutexattr-printers.py101
-rw-r--r--nptl/test-rwlock-printers.c78
-rw-r--r--nptl/test-rwlock-printers.py64
-rw-r--r--nptl/test-rwlockattr-printers.c98
-rw-r--r--nptl/test-rwlockattr-printers.py73
15 files changed, 1804 insertions, 0 deletions
diff --git a/nptl/Makefile b/nptl/Makefile
index 11588fe996..7ac9196975 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -312,6 +312,24 @@ gen-as-const-headers = pthread-errnos.sym \
 		       unwindbuf.sym \
 		       lowlevelrobustlock.sym pthread-pi-defines.sym
 
+gen-py-const-headers := nptl_lock_constants.pysym
+pretty-printers := nptl-printers.py
+tests-printers := test-mutexattr-printers test-mutex-printers \
+		  test-condattr-printers test-cond-printers \
+		  test-rwlockattr-printers test-rwlock-printers
+
+CFLAGS-test-mutexattr-printers.c := $(CFLAGS-printers-tests)
+CFLAGS-test-mutex-printers.c := $(CFLAGS-printers-tests)
+CFLAGS-test-condattr-printers.c := $(CFLAGS-printers-tests)
+CFLAGS-test-cond-printers.c := $(CFLAGS-printers-tests)
+CFLAGS-test-rwlockattr-printers.c := $(CFLAGS-printers-tests)
+CFLAGS-test-rwlock-printers.c := $(CFLAGS-printers-tests)
+
+ifeq ($(build-shared),yes)
+tests-printers-libs := $(shared-thread-library)
+else
+tests-printers-libs := $(static-thread-library)
+endif
 
 LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
 
diff --git a/nptl/nptl-printers.py b/nptl/nptl-printers.py
new file mode 100644
index 0000000000..e402f232c7
--- /dev/null
+++ b/nptl/nptl-printers.py
@@ -0,0 +1,633 @@
+# Pretty printers for the NPTL lock types.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+"""This file contains the gdb pretty printers for the following types:
+
+    * pthread_mutex_t
+    * pthread_mutexattr_t
+    * pthread_cond_t
+    * pthread_condattr_t
+    * pthread_rwlock_t
+    * pthread_rwlockattr_t
+
+You can check which printers are registered and enabled by issuing the
+'info pretty-printer' gdb command.  Printers should trigger automatically when
+trying to print a variable of one of the types mentioned above.
+"""
+
+from __future__ import print_function
+
+import gdb
+import gdb.printing
+from nptl_lock_constants import *
+
+MUTEX_TYPES = {
+    PTHREAD_MUTEX_NORMAL: ('Type', 'Normal'),
+    PTHREAD_MUTEX_RECURSIVE: ('Type', 'Recursive'),
+    PTHREAD_MUTEX_ERRORCHECK: ('Type', 'Error check'),
+    PTHREAD_MUTEX_ADAPTIVE_NP: ('Type', 'Adaptive')
+}
+
+class MutexPrinter(object):
+    """Pretty printer for pthread_mutex_t."""
+
+    def __init__(self, mutex):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            mutex: A gdb.value representing a pthread_mutex_t.
+        """
+
+        data = mutex['__data']
+        self.lock = data['__lock']
+        self.count = data['__count']
+        self.owner = data['__owner']
+        self.kind = data['__kind']
+        self.values = []
+        self.read_values()
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_mutex_t.
+        """
+
+        return 'pthread_mutex_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_mutex_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the mutex's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        self.read_type()
+        self.read_status()
+        self.read_attributes()
+        self.read_misc_info()
+
+    def read_type(self):
+        """Read the mutex's type."""
+
+        mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
+
+        # mutex_type must be casted to int because it's a gdb.Value
+        self.values.append(MUTEX_TYPES[int(mutex_type)])
+
+    def read_status(self):
+        """Read the mutex's status.
+
+        For architectures which support lock elision, this method reads
+        whether the mutex appears as locked in memory (i.e. it may show it as
+        unlocked even after calling pthread_mutex_lock).
+        """
+
+        if self.kind == PTHREAD_MUTEX_DESTROYED:
+            self.values.append(('Status', 'Destroyed'))
+        elif self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+            self.read_status_robust()
+        else:
+            self.read_status_no_robust()
+
+    def read_status_robust(self):
+        """Read the status of a robust mutex.
+
+        In glibc robust mutexes are implemented in a very different way than
+        non-robust ones.  This method reads their locking status,
+        whether it may have waiters, their registered owner (if any),
+        whether the owner is alive or not, and the status of the state
+        they're protecting.
+        """
+
+        if self.lock == PTHREAD_MUTEX_UNLOCKED:
+            self.values.append(('Status', 'Unlocked'))
+        else:
+            if self.lock & FUTEX_WAITERS:
+                self.values.append(('Status', 'Locked, possibly with waiters'))
+            else:
+                self.values.append(('Status',
+                                    'Locked, possibly with no waiters'))
+
+            if self.lock & FUTEX_OWNER_DIED:
+                self.values.append(('Owner ID', '%d (dead)' % self.owner))
+            else:
+                self.values.append(('Owner ID', self.lock & FUTEX_TID_MASK))
+
+        if self.owner == PTHREAD_MUTEX_INCONSISTENT:
+            self.values.append(('State protected by this mutex',
+                                'Inconsistent'))
+        elif self.owner == PTHREAD_MUTEX_NOTRECOVERABLE:
+            self.values.append(('State protected by this mutex',
+                                'Not recoverable'))
+
+    def read_status_no_robust(self):
+        """Read the status of a non-robust mutex.
+
+        Read info on whether the mutex is locked, if it may have waiters
+        and its owner (if any).
+        """
+
+        lock_value = self.lock
+
+        if self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
+            lock_value &= ~(PTHREAD_MUTEX_PRIO_CEILING_MASK)
+
+        if lock_value == PTHREAD_MUTEX_UNLOCKED:
+            self.values.append(('Status', 'Unlocked'))
+        else:
+            if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
+                waiters = self.lock & FUTEX_WAITERS
+                owner = self.lock & FUTEX_TID_MASK
+            else:
+                # Mutex protocol is PP or none
+                waiters = (self.lock != PTHREAD_MUTEX_LOCKED_NO_WAITERS)
+                owner = self.owner
+
+            if waiters:
+                self.values.append(('Status', 'Locked, possibly with waiters'))
+            else:
+                self.values.append(('Status',
+                                    'Locked, possibly with no waiters'))
+
+            self.values.append(('Owner ID', owner))
+
+    def read_attributes(self):
+        """Read the mutex's attributes."""
+
+        if self.kind != PTHREAD_MUTEX_DESTROYED:
+            if self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
+                self.values.append(('Robust', 'Yes'))
+            else:
+                self.values.append(('Robust', 'No'))
+
+            # In glibc, robust mutexes always have their pshared flag set to
+            # 'shared' regardless of what the pshared flag of their
+            # mutexattr was.  Therefore a robust mutex will act as shared
+            # even if it was initialized with a 'private' mutexattr.
+            if self.kind & PTHREAD_MUTEX_PSHARED_BIT:
+                self.values.append(('Shared', 'Yes'))
+            else:
+                self.values.append(('Shared', 'No'))
+
+            if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
+                self.values.append(('Protocol', 'Priority inherit'))
+            elif self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
+                prio_ceiling = ((self.lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
+                                >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT)
+
+                self.values.append(('Protocol', 'Priority protect'))
+                self.values.append(('Priority ceiling', prio_ceiling))
+            else:
+                # PTHREAD_PRIO_NONE
+                self.values.append(('Protocol', 'None'))
+
+    def read_misc_info(self):
+        """Read miscellaneous info on the mutex.
+
+        For now this reads the number of times a recursive mutex was locked
+        by the same thread.
+        """
+
+        mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
+
+        if mutex_type == PTHREAD_MUTEX_RECURSIVE and self.count > 1:
+            self.values.append(('Times locked recursively', self.count))
+
+class MutexAttributesPrinter(object):
+    """Pretty printer for pthread_mutexattr_t.
+
+    In the NPTL this is a type that's always casted to struct pthread_mutexattr
+    which has a single 'mutexkind' field containing the actual attributes.
+    """
+
+    def __init__(self, mutexattr):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            mutexattr: A gdb.value representing a pthread_mutexattr_t.
+        """
+
+        self.values = []
+
+        try:
+            mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr')
+            self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind']
+            self.read_values()
+        except gdb.error:
+            # libpthread doesn't have debug symbols, thus we can't find the
+            # real struct type.  Just print the union members.
+            self.values.append(('__size', mutexattr['__size']))
+            self.values.append(('__align', mutexattr['__align']))
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_mutexattr_t.
+        """
+
+        return 'pthread_mutexattr_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_mutexattr_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the mutexattr's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        mutexattr_type = (self.mutexattr
+                          & ~PTHREAD_MUTEXATTR_FLAG_BITS
+                          & ~PTHREAD_MUTEX_NO_ELISION_NP)
+
+        # mutexattr_type must be casted to int because it's a gdb.Value
+        self.values.append(MUTEX_TYPES[int(mutexattr_type)])
+
+        if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_ROBUST:
+            self.values.append(('Robust', 'Yes'))
+        else:
+            self.values.append(('Robust', 'No'))
+
+        if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
+            self.values.append(('Shared', 'Yes'))
+        else:
+            self.values.append(('Shared', 'No'))
+
+        protocol = ((self.mutexattr & PTHREAD_MUTEXATTR_PROTOCOL_MASK) >>
+                    PTHREAD_MUTEXATTR_PROTOCOL_SHIFT)
+
+        if protocol == PTHREAD_PRIO_NONE:
+            self.values.append(('Protocol', 'None'))
+        elif protocol == PTHREAD_PRIO_INHERIT:
+            self.values.append(('Protocol', 'Priority inherit'))
+        elif protocol == PTHREAD_PRIO_PROTECT:
+            self.values.append(('Protocol', 'Priority protect'))
+
+CLOCK_IDS = {
+    CLOCK_REALTIME: 'CLOCK_REALTIME',
+    CLOCK_MONOTONIC: 'CLOCK_MONOTONIC',
+    CLOCK_PROCESS_CPUTIME_ID: 'CLOCK_PROCESS_CPUTIME_ID',
+    CLOCK_THREAD_CPUTIME_ID: 'CLOCK_THREAD_CPUTIME_ID',
+    CLOCK_MONOTONIC_RAW: 'CLOCK_MONOTONIC_RAW',
+    CLOCK_REALTIME_COARSE: 'CLOCK_REALTIME_COARSE',
+    CLOCK_MONOTONIC_COARSE: 'CLOCK_MONOTONIC_COARSE'
+}
+
+class ConditionVariablePrinter(object):
+    """Pretty printer for pthread_cond_t."""
+
+    def __init__(self, cond):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            cond: A gdb.value representing a pthread_cond_t.
+        """
+
+        # Since PTHREAD_COND_SHARED is an integer, we need to cast it to void *
+        # to be able to compare it to the condvar's __data.__mutex member.
+        #
+        # While it looks like self.shared_value should be a class variable,
+        # that would result in it having an incorrect size if we're loading
+        # these printers through .gdbinit for a 64-bit objfile in AMD64.
+        # This is because gdb initially assumes the pointer size to be 4 bytes,
+        # and only sets it to 8 after loading the 64-bit objfiles.  Since
+        # .gdbinit runs before any objfiles are loaded, this would effectively
+        # make self.shared_value have a size of 4, thus breaking later
+        # comparisons with pointers whose types are looked up at runtime.
+        void_ptr_type = gdb.lookup_type('void').pointer()
+        self.shared_value = gdb.Value(PTHREAD_COND_SHARED).cast(void_ptr_type)
+
+        data = cond['__data']
+        self.total_seq = data['__total_seq']
+        self.mutex = data['__mutex']
+        self.nwaiters = data['__nwaiters']
+        self.values = []
+
+        self.read_values()
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_cond_t.
+        """
+
+        return 'pthread_cond_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_cond_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the condvar's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        self.read_status()
+        self.read_attributes()
+        self.read_mutex_info()
+
+    def read_status(self):
+        """Read the status of the condvar.
+
+        This method reads whether the condvar is destroyed and how many threads
+        are waiting for it.
+        """
+
+        if self.total_seq == PTHREAD_COND_DESTROYED:
+            self.values.append(('Status', 'Destroyed'))
+
+        self.values.append(('Threads waiting for this condvar',
+                            self.nwaiters >> COND_NWAITERS_SHIFT))
+
+    def read_attributes(self):
+        """Read the condvar's attributes."""
+
+        clock_id = self.nwaiters & ((1 << COND_NWAITERS_SHIFT) - 1)
+
+        # clock_id must be casted to int because it's a gdb.Value
+        self.values.append(('Clock ID', CLOCK_IDS[int(clock_id)]))
+
+        shared = (self.mutex == self.shared_value)
+
+        if shared:
+            self.values.append(('Shared', 'Yes'))
+        else:
+            self.values.append(('Shared', 'No'))
+
+    def read_mutex_info(self):
+        """Read the data of the mutex this condvar is bound to.
+
+        A pthread_cond_t's __data.__mutex member is a void * which
+        must be casted to pthread_mutex_t *.  For shared condvars, this
+        member isn't recorded and has a special value instead.
+        """
+
+        if self.mutex and self.mutex != self.shared_value:
+            mutex_type = gdb.lookup_type('pthread_mutex_t')
+            mutex = self.mutex.cast(mutex_type.pointer()).dereference()
+
+            self.values.append(('Mutex', mutex))
+
+class ConditionVariableAttributesPrinter(object):
+    """Pretty printer for pthread_condattr_t.
+
+    In the NPTL this is a type that's always casted to struct pthread_condattr,
+    which has a single 'value' field containing the actual attributes.
+    """
+
+    def __init__(self, condattr):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            condattr: A gdb.value representing a pthread_condattr_t.
+        """
+
+        self.values = []
+
+        try:
+            condattr_struct = gdb.lookup_type('struct pthread_condattr')
+            self.condattr = condattr.cast(condattr_struct)['value']
+            self.read_values()
+        except gdb.error:
+            # libpthread doesn't have debug symbols, thus we can't find the
+            # real struct type.  Just print the union members.
+            self.values.append(('__size', condattr['__size']))
+            self.values.append(('__align', condattr['__align']))
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_condattr_t.
+        """
+
+        return 'pthread_condattr_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_condattr_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the condattr's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        clock_id = self.condattr & ((1 << COND_NWAITERS_SHIFT) - 1)
+
+        # clock_id must be casted to int because it's a gdb.Value
+        self.values.append(('Clock ID', CLOCK_IDS[int(clock_id)]))
+
+        if self.condattr & 1:
+            self.values.append(('Shared', 'Yes'))
+        else:
+            self.values.append(('Shared', 'No'))
+
+class RWLockPrinter(object):
+    """Pretty printer for pthread_rwlock_t."""
+
+    def __init__(self, rwlock):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            rwlock: A gdb.value representing a pthread_rwlock_t.
+        """
+
+        data = rwlock['__data']
+        self.readers = data['__nr_readers']
+        self.queued_readers = data['__nr_readers_queued']
+        self.queued_writers = data['__nr_writers_queued']
+        self.writer_id = data['__writer']
+        self.shared = data['__shared']
+        self.prefers_writers = data['__flags']
+        self.values = []
+        self.read_values()
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_rwlock_t.
+        """
+
+        return 'pthread_rwlock_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_rwlock_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the rwlock's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        self.read_status()
+        self.read_attributes()
+
+    def read_status(self):
+        """Read the status of the rwlock."""
+
+        # Right now pthread_rwlock_destroy doesn't do anything, so there's no
+        # way to check if an rwlock is destroyed.
+
+        if self.writer_id:
+            self.values.append(('Status', 'Locked (Write)'))
+            self.values.append(('Writer ID', self.writer_id))
+        elif self.readers:
+            self.values.append(('Status', 'Locked (Read)'))
+            self.values.append(('Readers', self.readers))
+        else:
+            self.values.append(('Status', 'Unlocked'))
+
+        self.values.append(('Queued readers', self.queued_readers))
+        self.values.append(('Queued writers', self.queued_writers))
+
+    def read_attributes(self):
+        """Read the attributes of the rwlock."""
+
+        if self.shared:
+            self.values.append(('Shared', 'Yes'))
+        else:
+            self.values.append(('Shared', 'No'))
+
+        if self.prefers_writers:
+            self.values.append(('Prefers', 'Writers'))
+        else:
+            self.values.append(('Prefers', 'Readers'))
+
+class RWLockAttributesPrinter(object):
+    """Pretty printer for pthread_rwlockattr_t.
+
+    In the NPTL this is a type that's always casted to
+    struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
+    containing the actual attributes.
+    """
+
+    def __init__(self, rwlockattr):
+        """Initialize the printer's internal data structures.
+
+        Args:
+            rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
+        """
+
+        self.values = []
+
+        try:
+            rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
+            self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
+            self.read_values()
+        except gdb.error:
+            # libpthread doesn't have debug symbols, thus we can't find the
+            # real struct type.  Just print the union members.
+            self.values.append(('__size', rwlockattr['__size']))
+            self.values.append(('__align', rwlockattr['__align']))
+
+    def to_string(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_rwlockattr_t.
+        """
+
+        return 'pthread_rwlockattr_t'
+
+    def children(self):
+        """gdb API function.
+
+        This is called from gdb when we try to print a pthread_rwlockattr_t.
+        """
+
+        return self.values
+
+    def read_values(self):
+        """Read the rwlockattr's info and store it in self.values.
+
+        The data contained in self.values will be returned by the Iterator
+        created in self.children.
+        """
+
+        rwlock_type = self.rwlockattr['lockkind']
+        shared = self.rwlockattr['pshared']
+
+        if shared == PTHREAD_PROCESS_SHARED:
+            self.values.append(('Shared', 'Yes'))
+        else:
+            # PTHREAD_PROCESS_PRIVATE
+            self.values.append(('Shared', 'No'))
+
+        if (rwlock_type == PTHREAD_RWLOCK_PREFER_READER_NP or
+            rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NP):
+            # This is a known bug.  Using PTHREAD_RWLOCK_PREFER_WRITER_NP will
+            # still make the rwlock prefer readers.
+            self.values.append(('Prefers', 'Readers'))
+        elif rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:
+            self.values.append(('Prefers', 'Writers'))
+
+def register(objfile):
+    """Register the pretty printers within the given objfile."""
+
+    printer = gdb.printing.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
+
+    printer.add_printer('pthread_mutex_t', r'^pthread_mutex_t$',
+                        MutexPrinter)
+    printer.add_printer('pthread_mutexattr_t', r'^pthread_mutexattr_t$',
+                        MutexAttributesPrinter)
+    printer.add_printer('pthread_cond_t', r'^pthread_cond_t$',
+                        ConditionVariablePrinter)
+    printer.add_printer('pthread_condattr_t', r'^pthread_condattr_t$',
+                        ConditionVariableAttributesPrinter)
+    printer.add_printer('pthread_rwlock_t', r'^pthread_rwlock_t$',
+                        RWLockPrinter)
+    printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
+                        RWLockAttributesPrinter)
+
+    if objfile == None:
+        objfile = gdb
+
+    gdb.printing.register_pretty_printer(objfile, printer)
+
+register(gdb.current_objfile())
diff --git a/nptl/nptl_lock_constants.pysym b/nptl/nptl_lock_constants.pysym
new file mode 100644
index 0000000000..303ec61213
--- /dev/null
+++ b/nptl/nptl_lock_constants.pysym
@@ -0,0 +1,75 @@
+#include <pthreadP.h>
+
+-- Mutex types
+PTHREAD_MUTEX_KIND_MASK          PTHREAD_MUTEX_KIND_MASK_NP
+PTHREAD_MUTEX_NORMAL
+PTHREAD_MUTEX_RECURSIVE          PTHREAD_MUTEX_RECURSIVE_NP
+PTHREAD_MUTEX_ERRORCHECK         PTHREAD_MUTEX_ERRORCHECK_NP
+PTHREAD_MUTEX_ADAPTIVE_NP
+
+-- Mutex status
+-- These are hardcoded all over the code; there are no enums/macros for them.
+PTHREAD_MUTEX_DESTROYED         -1
+PTHREAD_MUTEX_UNLOCKED           0
+PTHREAD_MUTEX_LOCKED_NO_WAITERS  1
+
+-- For robust mutexes
+PTHREAD_MUTEX_INCONSISTENT
+PTHREAD_MUTEX_NOTRECOVERABLE
+FUTEX_OWNER_DIED
+
+-- For robust and PI mutexes
+FUTEX_WAITERS
+FUTEX_TID_MASK
+
+-- Mutex attributes
+PTHREAD_MUTEX_ROBUST_NORMAL_NP
+PTHREAD_MUTEX_PRIO_INHERIT_NP
+PTHREAD_MUTEX_PRIO_PROTECT_NP
+PTHREAD_MUTEX_PSHARED_BIT
+PTHREAD_MUTEX_PRIO_CEILING_SHIFT
+PTHREAD_MUTEX_PRIO_CEILING_MASK
+
+-- Mutex attribute flags
+PTHREAD_MUTEXATTR_PROTOCOL_SHIFT
+PTHREAD_MUTEXATTR_PROTOCOL_MASK
+PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
+PTHREAD_MUTEXATTR_FLAG_ROBUST
+PTHREAD_MUTEXATTR_FLAG_PSHARED
+PTHREAD_MUTEXATTR_FLAG_BITS
+PTHREAD_MUTEX_NO_ELISION_NP
+
+-- Priority protocols
+PTHREAD_PRIO_NONE
+PTHREAD_PRIO_INHERIT
+PTHREAD_PRIO_PROTECT
+
+-- These values are hardcoded as well:
+-- Value of __mutex for shared condvars.
+PTHREAD_COND_SHARED             (void *)~0l
+
+-- Value of __total_seq for destroyed condvars.
+PTHREAD_COND_DESTROYED          -1ull
+
+-- __nwaiters encodes the number of threads waiting on a condvar
+-- and the clock ID.
+-- __nwaiters >> COND_NWAITERS_SHIFT gives us the number of waiters.
+COND_NWAITERS_SHIFT
+
+-- Condvar clock IDs
+CLOCK_REALTIME
+CLOCK_MONOTONIC
+CLOCK_PROCESS_CPUTIME_ID
+CLOCK_THREAD_CPUTIME_ID
+CLOCK_MONOTONIC_RAW
+CLOCK_REALTIME_COARSE
+CLOCK_MONOTONIC_COARSE
+
+-- Rwlock attributes
+PTHREAD_RWLOCK_PREFER_READER_NP
+PTHREAD_RWLOCK_PREFER_WRITER_NP
+PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+
+-- 'Shared' attribute values
+PTHREAD_PROCESS_PRIVATE
+PTHREAD_PROCESS_SHARED
diff --git a/nptl/test-cond-printers.c b/nptl/test-cond-printers.c
new file mode 100644
index 0000000000..0f2a5f4827
--- /dev/null
+++ b/nptl/test-cond-printers.c
@@ -0,0 +1,57 @@
+/* Helper program for testing the pthread_cond_t pretty printer.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <time.h>
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+
+static int test_status_destroyed (pthread_cond_t *condvar);
+
+int
+main (void)
+{
+  pthread_cond_t condvar;
+  pthread_condattr_t attr;
+  int result = FAIL;
+
+  if (pthread_condattr_init (&attr) == 0
+      && test_status_destroyed (&condvar) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_cond* functions failed.  */
+
+  return result;
+}
+
+/* Initializes CONDVAR, then destroys it.  */
+static int
+test_status_destroyed (pthread_cond_t *condvar)
+{
+  int result = FAIL;
+
+  if (pthread_cond_init (condvar, NULL) == 0
+      && pthread_cond_destroy (condvar) == 0)
+    result = PASS; /* Test status (destroyed).  */
+
+  return result;
+}
diff --git a/nptl/test-cond-printers.py b/nptl/test-cond-printers.py
new file mode 100644
index 0000000000..af0e12eb97
--- /dev/null
+++ b/nptl/test-cond-printers.py
@@ -0,0 +1,50 @@
+# Common tests for the ConditionVariablePrinter class.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    var = 'condvar'
+    to_string = 'pthread_cond_t'
+
+    break_at(test_source, 'Test status (destroyed)')
+    continue_cmd() # Go to test_status_destroyed
+    test_printer(var, to_string, {'Status': 'Destroyed'})
+
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)
diff --git a/nptl/test-condattr-printers.c b/nptl/test-condattr-printers.c
new file mode 100644
index 0000000000..4db4098827
--- /dev/null
+++ b/nptl/test-condattr-printers.c
@@ -0,0 +1,94 @@
+/* Helper program for testing the pthread_cond_t and pthread_condattr_t
+   pretty printers.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <time.h>
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+
+static int condvar_reinit (pthread_cond_t *condvar,
+			   const pthread_condattr_t *attr);
+static int test_setclock (pthread_cond_t *condvar, pthread_condattr_t *attr);
+static int test_setpshared (pthread_cond_t *condvar, pthread_condattr_t *attr);
+
+/* Need these so we don't have lines longer than 79 chars.  */
+#define SET_SHARED(attr, shared) pthread_condattr_setpshared (attr, shared)
+
+int
+main (void)
+{
+  pthread_cond_t condvar;
+  pthread_condattr_t attr;
+  int result = FAIL;
+
+  if (pthread_condattr_init (&attr) == 0
+      && pthread_cond_init (&condvar, NULL) == 0
+      && test_setclock (&condvar, &attr) == PASS
+      && test_setpshared (&condvar, &attr) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_cond* functions failed.  */
+
+  return result;
+}
+
+/* Destroys CONDVAR and re-initializes it using ATTR.  */
+static int
+condvar_reinit (pthread_cond_t *condvar, const pthread_condattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_cond_destroy (condvar) == 0
+      && pthread_cond_init (condvar, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting the clock ID attribute.  */
+static int
+test_setclock (pthread_cond_t *condvar, pthread_condattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_condattr_setclock (attr, CLOCK_REALTIME) == 0 /* Set clock.  */
+      && condvar_reinit (condvar, attr) == PASS)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting whether the condvar can be shared between processes.  */
+static int
+test_setpshared (pthread_cond_t *condvar, pthread_condattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared.  */
+      && condvar_reinit (condvar, attr) == PASS
+      && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
+      && condvar_reinit (condvar, attr) == PASS)
+    result = PASS;
+
+  return result;
+}
diff --git a/nptl/test-condattr-printers.py b/nptl/test-condattr-printers.py
new file mode 100644
index 0000000000..7ea01db158
--- /dev/null
+++ b/nptl/test-condattr-printers.py
@@ -0,0 +1,71 @@
+# Common tests for the ConditionVariablePrinter and
+# ConditionVariableAttributesPrinter classes.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    check_debug_symbol('struct pthread_condattr')
+
+    condvar_var = 'condvar'
+    condvar_to_string = 'pthread_cond_t'
+
+    attr_var = 'attr'
+    attr_to_string = 'pthread_condattr_t'
+
+    break_at(test_source, 'Set clock')
+    continue_cmd() # Go to test_setclock
+    next_cmd(2)
+    test_printer(condvar_var, condvar_to_string, {'Clock ID': 'CLOCK_REALTIME'})
+    test_printer(attr_var, attr_to_string, {'Clock ID': 'CLOCK_REALTIME'})
+
+    break_at(test_source, 'Set shared')
+    continue_cmd() # Go to test_setpshared
+    next_cmd(2)
+    test_printer(condvar_var, condvar_to_string, {'Shared': 'Yes'})
+    test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
+    next_cmd(2)
+    test_printer(condvar_var, condvar_to_string, {'Shared': 'No'})
+    test_printer(attr_var, attr_to_string, {'Shared': 'No'})
+
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+except DebugError as exception:
+    print(exception)
+    result = UNSUPPORTED
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)
diff --git a/nptl/test-mutex-printers.c b/nptl/test-mutex-printers.c
new file mode 100644
index 0000000000..b973e82840
--- /dev/null
+++ b/nptl/test-mutex-printers.c
@@ -0,0 +1,151 @@
+/* Helper program for testing the pthread_mutex_t pretty printer.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+
+static int test_status_destroyed (pthread_mutex_t *mutex);
+static int test_status_no_robust (pthread_mutex_t *mutex,
+				  pthread_mutexattr_t *attr);
+static int test_status_robust (pthread_mutex_t *mutex,
+			       pthread_mutexattr_t *attr);
+static int test_locking_state_robust (pthread_mutex_t *mutex);
+static void *thread_func (void *arg);
+static int test_recursive_locks (pthread_mutex_t *mutex,
+				 pthread_mutexattr_t *attr);
+
+int
+main (void)
+{
+  pthread_mutex_t mutex;
+  pthread_mutexattr_t attr;
+  int result = FAIL;
+
+  if (pthread_mutexattr_init (&attr) == 0
+      && test_status_destroyed (&mutex) == PASS
+      && test_status_no_robust (&mutex, &attr) == PASS
+      && test_status_robust (&mutex, &attr) == PASS
+      && test_recursive_locks (&mutex, &attr) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_mutex* functions failed.  */
+
+  return result;
+}
+
+/* Initializes MUTEX, then destroys it.  */
+static int
+test_status_destroyed (pthread_mutex_t *mutex)
+{
+  int result = FAIL;
+
+  if (pthread_mutex_init (mutex, NULL) == 0
+      && pthread_mutex_destroy (mutex) == 0)
+    result = PASS; /* Test status (destroyed).  */
+
+  return result;
+}
+
+/* Tests locking of non-robust mutexes.  */
+static int
+test_status_no_robust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_mutexattr_setrobust (attr, PTHREAD_MUTEX_STALLED) == 0
+      && pthread_mutex_init (mutex, attr) == 0
+      && pthread_mutex_lock (mutex) == 0 /* Test status (non-robust).  */
+      && pthread_mutex_unlock (mutex) == 0
+      && pthread_mutex_destroy (mutex) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests locking of robust mutexes.  */
+static int
+test_status_robust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_mutexattr_setrobust (attr, PTHREAD_MUTEX_ROBUST) == 0
+      && pthread_mutex_init (mutex, attr) == 0
+      && test_locking_state_robust (mutex) == PASS /* Test status (robust).  */
+      && pthread_mutex_destroy (mutex) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests locking and state corruption of robust mutexes.  We'll mark it as
+   inconsistent, then not recoverable.  */
+static int
+test_locking_state_robust (pthread_mutex_t *mutex)
+{
+  int result = FAIL;
+  pthread_t thread;
+
+  if (pthread_create (&thread, NULL, thread_func, mutex) == 0 /* Create.  */
+      && pthread_join (thread, NULL) == 0
+      && pthread_mutex_lock (mutex) == EOWNERDEAD /* Test locking (robust).  */
+      && pthread_mutex_unlock (mutex) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Function to be called by the child thread when testing robust mutexes.  */
+static void *
+thread_func (void *arg)
+{
+  pthread_mutex_t *mutex = (pthread_mutex_t *)arg;
+
+  if (pthread_mutex_lock (mutex) != 0) /* Thread function.  */
+    exit (FAIL);
+
+  /* Thread terminates without unlocking the mutex, thus marking it as
+     inconsistent.  */
+  return NULL;
+}
+
+/* Tests locking the mutex multiple times in a row.  */
+static int
+test_recursive_locks (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_mutexattr_settype (attr, PTHREAD_MUTEX_RECURSIVE) == 0
+      && pthread_mutex_init (mutex, attr) == 0
+      && pthread_mutex_lock (mutex) == 0
+      && pthread_mutex_lock (mutex) == 0
+      && pthread_mutex_lock (mutex) == 0 /* Test recursive locks.  */
+      && pthread_mutex_unlock (mutex) == 0
+      && pthread_mutex_unlock (mutex) == 0
+      && pthread_mutex_unlock (mutex) == 0
+      && pthread_mutex_destroy (mutex) == 0)
+    result = PASS;
+
+  return result;
+}
diff --git a/nptl/test-mutex-printers.py b/nptl/test-mutex-printers.py
new file mode 100644
index 0000000000..7f542adcd7
--- /dev/null
+++ b/nptl/test-mutex-printers.py
@@ -0,0 +1,97 @@
+# Tests for the MutexPrinter class.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    var = 'mutex'
+    to_string = 'pthread_mutex_t'
+
+    break_at(test_source, 'Test status (destroyed)')
+    continue_cmd() # Go to test_status_destroyed
+    test_printer(var, to_string, {'Status': 'Destroyed'})
+
+    break_at(test_source, 'Test status (non-robust)')
+    continue_cmd() # Go to test_status_no_robust
+    test_printer(var, to_string, {'Status': 'Unlocked'})
+    next_cmd()
+    thread_id = get_current_thread_lwpid()
+    test_printer(var, to_string, {'Status': 'Locked, possibly with no waiters',
+                                  'Owner ID': thread_id})
+
+    break_at(test_source, 'Test status (robust)')
+    continue_cmd() # Go to test_status_robust
+    test_printer(var, to_string, {'Status': 'Unlocked'})
+
+    # We'll now test the robust mutex locking states.  We'll create a new
+    # thread that will lock a robust mutex and exit without unlocking it.
+    break_at(test_source, 'Create')
+    continue_cmd() # Go to test_locking_state_robust
+    # Set a breakpoint for the new thread to hit.
+    break_at(test_source, 'Thread function')
+    continue_cmd()
+    # By now the new thread is created and has hit its breakpoint.
+    set_scheduler_locking(True)
+    parent = 1
+    child = 2
+    select_thread(child)
+    child_id = get_current_thread_lwpid()
+    # We've got the new thread's ID.
+    select_thread(parent)
+    # Make the new thread finish its function while we wait.
+    continue_cmd(thread=child)
+    # The new thread should be dead by now.
+    break_at(test_source, 'Test locking (robust)')
+    continue_cmd()
+    test_printer(var, to_string, {'Owner ID': r'{0} \(dead\)'.format(child_id)})
+    # Try to lock and unlock the mutex.
+    next_cmd()
+    test_printer(var, to_string, {'Owner ID': thread_id,
+                           'State protected by this mutex': 'Inconsistent'})
+    next_cmd()
+    test_printer(var, to_string, {'Status': 'Unlocked',
+                        'State protected by this mutex': 'Not recoverable'})
+    set_scheduler_locking(False)
+
+    break_at(test_source, 'Test recursive locks')
+    continue_cmd() # Go to test_recursive_locks
+    test_printer(var, to_string, {'Times locked recursively': '2'})
+    next_cmd()
+    test_printer(var, to_string, {'Times locked recursively': '3'})
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)
diff --git a/nptl/test-mutexattr-printers.c b/nptl/test-mutexattr-printers.c
new file mode 100644
index 0000000000..9ecfff76c3
--- /dev/null
+++ b/nptl/test-mutexattr-printers.c
@@ -0,0 +1,144 @@
+/* Helper program for testing the pthread_mutex_t and pthread_mutexattr_t
+   pretty printers.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+#define PRIOCEILING 42
+
+/* Need these so we don't have lines longer than 79 chars.  */
+#define SET_TYPE(attr, type) pthread_mutexattr_settype (attr, type)
+#define SET_ROBUST(attr, robust) pthread_mutexattr_setrobust (attr, robust)
+#define SET_SHARED(attr, shared) pthread_mutexattr_setpshared (attr, shared)
+#define SET_PROTOCOL(attr, protocol) \
+	pthread_mutexattr_setprotocol (attr, protocol)
+#define SET_PRIOCEILING(mutex, prioceiling, old_ceiling) \
+	pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
+
+static int mutex_reinit (pthread_mutex_t *mutex,
+			 const pthread_mutexattr_t *attr);
+static int test_settype (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
+static int test_setrobust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
+static int test_setpshared (pthread_mutex_t *mutex, pthread_mutexattr_t *attr);
+static int test_setprotocol (pthread_mutex_t *mutex,
+			     pthread_mutexattr_t *attr);
+
+int
+main (void)
+{
+  pthread_mutex_t mutex;
+  pthread_mutexattr_t attr;
+  int result = FAIL;
+
+  if (pthread_mutexattr_init (&attr) == 0
+      && pthread_mutex_init (&mutex, NULL) == 0
+      && test_settype (&mutex, &attr) == PASS
+      && test_setrobust (&mutex, &attr) == PASS
+      && test_setpshared (&mutex, &attr) == PASS
+      && test_setprotocol (&mutex, &attr) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_mutex* functions failed.  */
+
+  return result;
+}
+
+/* Destroys MUTEX and re-initializes it using ATTR.  */
+static int
+mutex_reinit (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_mutex_destroy (mutex) == 0
+      && pthread_mutex_init (mutex, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting the mutex type.  */
+static int
+test_settype (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_TYPE (attr, PTHREAD_MUTEX_ERRORCHECK) == 0 /* Set type.  */
+      && mutex_reinit (mutex, attr) == 0
+      && SET_TYPE (attr, PTHREAD_MUTEX_RECURSIVE) == 0
+      && mutex_reinit (mutex, attr) == 0
+      && SET_TYPE (attr, PTHREAD_MUTEX_NORMAL) == 0
+      && mutex_reinit (mutex, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting whether the mutex is robust.  */
+static int
+test_setrobust (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_ROBUST (attr, PTHREAD_MUTEX_ROBUST) == 0 /* Set robust.  */
+      && mutex_reinit (mutex, attr) == 0
+      && SET_ROBUST (attr, PTHREAD_MUTEX_STALLED) == 0
+      && mutex_reinit (mutex, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting whether the mutex can be shared between processes.  */
+static int
+test_setpshared (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared.  */
+      && mutex_reinit (mutex, attr) == 0
+      && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
+      && mutex_reinit (mutex, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting the mutex protocol and, for Priority Protect, the Priority
+   Ceiling.  */
+static int
+test_setprotocol (pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+  int result = FAIL;
+  int old_prioceiling;
+
+  if (SET_PROTOCOL (attr, PTHREAD_PRIO_INHERIT) == 0 /* Set protocol.  */
+      && mutex_reinit (mutex, attr) == 0
+      && SET_PROTOCOL (attr, PTHREAD_PRIO_PROTECT) == 0
+      && mutex_reinit (mutex, attr) == 0
+      && SET_PRIOCEILING(mutex, PRIOCEILING, &old_prioceiling) == 0
+      && SET_PROTOCOL (attr, PTHREAD_PRIO_NONE) == 0
+      && mutex_reinit (mutex, attr) == 0)
+    result = PASS;
+
+  return result;
+}
diff --git a/nptl/test-mutexattr-printers.py b/nptl/test-mutexattr-printers.py
new file mode 100644
index 0000000000..4464723fbe
--- /dev/null
+++ b/nptl/test-mutexattr-printers.py
@@ -0,0 +1,101 @@
+# Common tests for the MutexPrinter and MutexAttributesPrinter classes.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+PRIOCEILING = 42
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    check_debug_symbol('struct pthread_mutexattr')
+
+    mutex_var = 'mutex'
+    mutex_to_string = 'pthread_mutex_t'
+
+    attr_var = 'attr'
+    attr_to_string = 'pthread_mutexattr_t'
+
+    break_at(test_source, 'Set type')
+    continue_cmd() # Go to test_settype
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Type': 'Error check'})
+    test_printer(mutex_var, mutex_to_string, {'Type': 'Error check'})
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Type': 'Recursive'})
+    test_printer(mutex_var, mutex_to_string, {'Type': 'Recursive'})
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Type': 'Normal'})
+    test_printer(mutex_var, mutex_to_string, {'Type': 'Normal'})
+
+    break_at(test_source, 'Set robust')
+    continue_cmd() # Go to test_setrobust
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Robust': 'Yes'})
+    test_printer(mutex_var, mutex_to_string, {'Robust': 'Yes'})
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Robust': 'No'})
+    test_printer(mutex_var, mutex_to_string, {'Robust': 'No'})
+
+    break_at(test_source, 'Set shared')
+    continue_cmd() # Go to test_setpshared
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
+    test_printer(mutex_var, mutex_to_string, {'Shared': 'Yes'})
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Shared': 'No'})
+    test_printer(mutex_var, mutex_to_string, {'Shared': 'No'})
+
+    break_at(test_source, 'Set protocol')
+    continue_cmd() # Go to test_setprotocol
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Protocol': 'Priority inherit'})
+    test_printer(mutex_var, mutex_to_string, {'Protocol': 'Priority inherit'})
+    next_cmd(2)
+    test_printer(attr_var, attr_to_string, {'Protocol': 'Priority protect'})
+    test_printer(mutex_var, mutex_to_string, {'Protocol': 'Priority protect'})
+    next_cmd(2)
+    test_printer(mutex_var, mutex_to_string, {'Priority ceiling':
+                                              str(PRIOCEILING)})
+    next_cmd()
+    test_printer(attr_var, attr_to_string, {'Protocol': 'None'})
+    test_printer(mutex_var, mutex_to_string, {'Protocol': 'None'})
+
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+except DebugError as exception:
+    print(exception)
+    result = UNSUPPORTED
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)
diff --git a/nptl/test-rwlock-printers.c b/nptl/test-rwlock-printers.c
new file mode 100644
index 0000000000..dbbe9b80d6
--- /dev/null
+++ b/nptl/test-rwlock-printers.c
@@ -0,0 +1,78 @@
+/* Helper program for testing the pthread_rwlock_t pretty printer.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+
+static int test_locking_reader (pthread_rwlock_t *rwlock);
+static int test_locking_writer (pthread_rwlock_t *rwlock);
+
+int
+main (void)
+{
+  pthread_rwlock_t rwlock;
+
+  int result = FAIL;
+
+  if (test_locking_reader (&rwlock) == PASS
+      && test_locking_writer (&rwlock) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_rwlock* functions failed.  */
+
+  return result;
+}
+
+/* Tests locking the rwlock multiple times as a reader.  */
+static int
+test_locking_reader (pthread_rwlock_t *rwlock)
+{
+  int result = FAIL;
+
+  if (pthread_rwlock_init (rwlock, NULL) == 0
+      && pthread_rwlock_rdlock (rwlock) == 0 /* Test locking (reader).  */
+      && pthread_rwlock_rdlock (rwlock) == 0
+      && pthread_rwlock_rdlock (rwlock) == 0
+      && pthread_rwlock_unlock (rwlock) == 0
+      && pthread_rwlock_unlock (rwlock) == 0
+      && pthread_rwlock_unlock (rwlock) == 0
+      && pthread_rwlock_destroy (rwlock) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests locking the rwlock as a writer.  */
+static int
+test_locking_writer (pthread_rwlock_t *rwlock)
+{
+  int result = FAIL;
+
+  if (pthread_rwlock_init (rwlock, NULL) == 0
+      && pthread_rwlock_wrlock (rwlock) == 0 /* Test locking (writer).  */
+      && pthread_rwlock_unlock (rwlock) == 0
+      && pthread_rwlock_destroy (rwlock) == 0)
+    result = PASS;
+
+  return result;
+}
diff --git a/nptl/test-rwlock-printers.py b/nptl/test-rwlock-printers.py
new file mode 100644
index 0000000000..b972fa60d0
--- /dev/null
+++ b/nptl/test-rwlock-printers.py
@@ -0,0 +1,64 @@
+# Common tests for the RWLockPrinter class.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    var = 'rwlock'
+    to_string = 'pthread_rwlock_t'
+
+    break_at(test_source, 'Test locking (reader)')
+    continue_cmd() # Go to test_locking_reader
+    test_printer(var, to_string, {'Status': 'Unlocked'})
+    next_cmd()
+    test_printer(var, to_string, {'Status': r'Locked \(Read\)', 'Readers': '1'})
+    next_cmd()
+    test_printer(var, to_string, {'Readers': '2'})
+    next_cmd()
+    test_printer(var, to_string, {'Readers': '3'})
+
+    break_at(test_source, 'Test locking (writer)')
+    continue_cmd() # Go to test_locking_writer
+    test_printer(var, to_string, {'Status': 'Unlocked'})
+    next_cmd()
+    thread_id = get_current_thread_lwpid()
+    test_printer(var, to_string, {'Status': r'Locked \(Write\)',
+                                  'Writer ID': thread_id})
+
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)
diff --git a/nptl/test-rwlockattr-printers.c b/nptl/test-rwlockattr-printers.c
new file mode 100644
index 0000000000..d12facf41c
--- /dev/null
+++ b/nptl/test-rwlockattr-printers.c
@@ -0,0 +1,98 @@
+/* Helper program for testing the pthread_rwlock_t and pthread_rwlockattr_t
+   pretty printers.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Keep the calls to the pthread_* functions on separate lines to make it easy
+   to advance through the program using the gdb 'next' command.  */
+
+#include <pthread.h>
+
+#define PASS 0
+#define FAIL 1
+
+/* Need these so we don't have lines longer than 79 chars.  */
+#define SET_KIND(attr, kind) pthread_rwlockattr_setkind_np (attr, kind)
+#define SET_SHARED(attr, shared) pthread_rwlockattr_setpshared (attr, shared)
+
+static int rwlock_reinit (pthread_rwlock_t *rwlock,
+			  const pthread_rwlockattr_t *attr);
+static int test_setkind_np (pthread_rwlock_t *rwlock,
+			    pthread_rwlockattr_t *attr);
+static int test_setpshared (pthread_rwlock_t *rwlock,
+			    pthread_rwlockattr_t *attr);
+
+int
+main (void)
+{
+  pthread_rwlock_t rwlock;
+  pthread_rwlockattr_t attr;
+  int result = FAIL;
+
+  if (pthread_rwlockattr_init (&attr) == 0
+      && pthread_rwlock_init (&rwlock, NULL) == 0
+      && test_setkind_np (&rwlock, &attr) == PASS
+      && test_setpshared (&rwlock, &attr) == PASS)
+    result = PASS;
+  /* Else, one of the pthread_rwlock* functions failed.  */
+
+  return result;
+}
+
+/* Destroys RWLOCK and re-initializes it using ATTR.  */
+static int
+rwlock_reinit (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
+{
+  int result = FAIL;
+
+  if (pthread_rwlock_destroy (rwlock) == 0
+      && pthread_rwlock_init (rwlock, attr) == 0)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting whether the rwlock prefers readers or writers.  */
+static int
+test_setkind_np (pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_KIND (attr, PTHREAD_RWLOCK_PREFER_READER_NP) == 0 /* Set kind.  */
+      && rwlock_reinit (rwlock, attr) == PASS
+      && SET_KIND (attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) == 0
+      && rwlock_reinit (rwlock, attr) == PASS)
+    result = PASS;
+
+  return result;
+}
+
+/* Tests setting whether the rwlock can be shared between processes.  */
+static int
+test_setpshared (pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr)
+{
+  int result = FAIL;
+
+  if (SET_SHARED (attr, PTHREAD_PROCESS_SHARED) == 0 /* Set shared.  */
+      && rwlock_reinit (rwlock, attr) == PASS
+      && SET_SHARED (attr, PTHREAD_PROCESS_PRIVATE) == 0
+      && rwlock_reinit (rwlock, attr) == PASS)
+    result = PASS;
+
+  return result;
+}
diff --git a/nptl/test-rwlockattr-printers.py b/nptl/test-rwlockattr-printers.py
new file mode 100644
index 0000000000..1ca2dc6c33
--- /dev/null
+++ b/nptl/test-rwlockattr-printers.py
@@ -0,0 +1,73 @@
+# Common tests for the RWLockPrinter and RWLockAttributesPrinter classes.
+#
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import sys
+
+from test_printers_common import *
+
+test_source = sys.argv[1]
+test_bin = sys.argv[2]
+printer_files = sys.argv[3:]
+printer_names = ['global glibc-pthread-locks']
+
+try:
+    init_test(test_bin, printer_files, printer_names)
+    go_to_main()
+
+    check_debug_symbol('struct pthread_rwlockattr')
+
+    rwlock_var = 'rwlock'
+    rwlock_to_string = 'pthread_rwlock_t'
+
+    attr_var = 'attr'
+    attr_to_string = 'pthread_rwlockattr_t'
+
+    break_at(test_source, 'Set kind')
+    continue_cmd() # Go to test_setkind_np
+    next_cmd(2)
+    test_printer(rwlock_var, rwlock_to_string, {'Prefers': 'Readers'})
+    test_printer(attr_var, attr_to_string, {'Prefers': 'Readers'})
+    next_cmd(2)
+    test_printer(rwlock_var, rwlock_to_string, {'Prefers': 'Writers'})
+    test_printer(attr_var, attr_to_string, {'Prefers': 'Writers'})
+
+    break_at(test_source, 'Set shared')
+    continue_cmd() # Go to test_setpshared
+    next_cmd(2)
+    test_printer(rwlock_var, rwlock_to_string, {'Shared': 'Yes'})
+    test_printer(attr_var, attr_to_string, {'Shared': 'Yes'})
+    next_cmd(2)
+    test_printer(rwlock_var, rwlock_to_string, {'Shared': 'No'})
+    test_printer(attr_var, attr_to_string, {'Shared': 'No'})
+
+    continue_cmd() # Exit
+
+except (NoLineError, pexpect.TIMEOUT) as exception:
+    print('Error: {0}'.format(exception))
+    result = FAIL
+
+except DebugError as exception:
+    print(exception)
+    result = UNSUPPORTED
+
+else:
+    print('Test succeeded.')
+    result = PASS
+
+exit(result)