@@ -1,3 +1,13 @@
+2015-10-09 Martin Galvan <martin.galvan@tallertechnologies.com>
+
+ * Makerules ($(common-objpfx)%.py): New target.
+ * nptl/Makefile (gen-py-const-headers): New define.
+ (install-bin-script): Add Python pretty printers.
+ ($(addprefix $(objpfx),$(install-bin-script))): New target.
+ * nptl/nptl-printers.py: New file.
+ * nptl/nptl_lock_constants.pysym: New file.
+ * scripts/gen-py-const.awk: New file.
+
2015-10-09 Adhemerval Zanella <adhemerval.zanella@linaro.org>
Phil Blundell <pb@pbcui.dot.net>
@@ -190,6 +190,34 @@ sed-remove-dotdot := -e 's@ *\([^ \/$$][^ \]*\)@ $$(..)\1@g' \
-e 's@^\([^ \/$$][^ \]*\)@$$(..)\1@g'
endif
+ifdef gen-py-const-headers
+# This is a hack we use to generate .py files with constants for Python
+# pretty-printers. It works the same way as gen-as-const. See gen-py-const
+# for details on how the awk | gcc mechanism works.
+$(common-objpfx)%.py: $(..)scripts/gen-py-const.awk %.pysym $(common-before-compile)
+ $(AWK) -f $< $(filter %.pysym,$^)
+ $(AWK) -f $< $(filter %.pysym,$^) \
+ | $(CC) -S -o $(addsuffix .tmp,$@) $(CFLAGS) $(CPPFLAGS) -x c -
+ echo '# GENERATED FILE, DO NOT EDIT\n' > $@
+ echo '# Constant definitions for the NPTL pretty printers.' >> $@
+ echo '# See gen-py-const.awk for details.\n' >> $@
+
+ # Replace "@name@SOME_NAME@value@SOME_VALUE@" strings from the output of
+ # gen-py-const.awk with "SOME_NAME = SOME_VALUE" strings.
+ # The '-n' option, combined with the '/p' command, makes sed output only the
+ # modified lines instead of the whole input file. The output is redirected
+ # to a .py file; we'll import it from printers.py to read the constants
+ # generated by gen-py-const.awk.
+ # The regex has two capturing groups, for SOME_NAME and SOME_VALUE
+ # respectively. Notice SOME_VALUE will start with a '$'; Make requires that
+ # we write '$' twice.
+ sed -n 's/^.*@name@\([^@]\+\)@value@\$$\([0-9Xxa-fA-F-]\+\)@.*/\1 = \2/p' \
+ $(addsuffix .tmp,$@) >> $@
+ rm -f $(addsuffix .tmp,$@)
+
+before-compile += $(patsubst %.pysym,%.py,$(common-objpfx)$(gen-py-const-headers))
+generated += $(patsubst %.pysym,%.py,$(common-objpfx)$(gen-py-const-headers))
+endif # gen-py-const-headers
ifdef gen-as-const-headers
# Generating headers for assembly constants.
@@ -304,6 +304,7 @@ gen-as-const-headers = pthread-errnos.sym \
lowlevelbarrier.sym unwindbuf.sym \
lowlevelrobustlock.sym pthread-pi-defines.sym
+gen-py-const-headers = nptl_lock_constants.pysym
LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
@@ -412,6 +413,16 @@ ifneq ($(have-cxx-thread_local),yes)
tests-unsupported += tst-thread_local1
endif
+# Install the Python pretty-printers.
+py-const = $(patsubst %.pysym,%.py,$(gen-py-const-headers))
+install-bin-script = $(py-const) nptl-printers.py
+
+# Copy the .py files into $(objpfx) so that the install-bin-script target
+# in Makerules can find them.
+$(addprefix $(objpfx),$(install-bin-script)): $(common-objpfx)$(py-const) \
+ nptl-printers.py
+ $(INSTALL) $^ $(objpfx)
+
include ../Rules
ifeq (yes,$(build-shared))
new file mode 100644
@@ -0,0 +1,671 @@
+# Copyright (C) 2015 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Martin Galvan <martin.galvan@tallertechnologies.com>
+#
+# 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/>.
+
+"""Pretty printers for the NTPL lock types.
+
+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.
+"""
+
+import sys
+import re
+import ctypes
+import gdb
+from nptl_lock_constants import *
+
+class _IteratorP3(object):
+ """A simple Iterator class."""
+
+ def __init__(self, values):
+ self.values = values
+ self.length = len(self.values)
+ self.count = 0
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ count = self.count
+ self.count += 1
+
+ if count == self.length:
+ raise StopIteration
+ else:
+ return self.values[count]
+
+class _IteratorP2(_IteratorP3):
+ """Hack for Python 2 compatibilty."""
+
+ def next(self):
+ self.__next__()
+
+# Hack for Python 2 compatibilty
+if sys.version_info[0] > 2:
+ Iterator = _IteratorP3
+else:
+ Iterator = _IteratorP2
+
+################################################################################
+
+mutexTypesDict = {
+ 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.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.readType()
+ self.readStatus()
+ self.readAttributes()
+ self.readMiscInfo()
+
+ def readType(self):
+ """Read the mutex's type."""
+
+ mutexType = self.kind & PTHREAD_MUTEX_KIND_MASK
+
+ # mutexType must be casted to int because it's a gdb.Value
+ self.values.append(mutexTypesDict[int(mutexType)])
+
+ def readStatus(self):
+ """Read the mutex's status.
+
+ For architectures which support lock elision, this method reads
+ whether the mutex is actually locked (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.readStatusRobust()
+ else:
+ self.readStatusNonRobust()
+
+ def readStatusRobust(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, 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 readStatusNonRobust(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).
+ """
+
+ if self.lock == 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, no waiters'))
+
+ self.values.append(('Owner ID', owner))
+
+ def readAttributes(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:
+ prioCeiling = ((self.lock & PTHREAD_MUTEX_PRIO_CEILING_MASK) >>
+ PTHREAD_MUTEX_PRIO_CEILING_SHIFT)
+
+ self.values.append(('Protocol', 'Priority protect'))
+ self.values.append(('Priority ceiling', prioCeiling))
+ else:
+ # PTHREAD_PRIO_NONE
+ self.values.append(('Protocol', 'None'))
+
+ def readMiscInfo(self):
+ """Read miscellaneous info on the mutex.
+
+ For now this reads the number of times a row a recursive mutex
+ was locked by the same thread.
+ """
+
+ mutexType = self.kind & PTHREAD_MUTEX_KIND_MASK
+
+ if mutexType == 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.
+ """
+
+ mutexattrStruct = gdb.lookup_type('struct pthread_mutexattr')
+ self.mutexattr = mutexattr.cast(mutexattrStruct)['mutexkind']
+ self.values = []
+ self.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.
+ """
+
+ mutexattrType = (self.mutexattr &
+ ~PTHREAD_MUTEXATTR_FLAG_BITS &
+ ~PTHREAD_MUTEX_NO_ELISION_NP)
+
+ # mutexattrType must be casted to int because it's a gdb.Value
+ self.values.append(mutexTypesDict[int(mutexattrType)])
+
+ 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'))
+
+################################################################################
+
+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.
+ """
+
+ data = cond['__data']
+ self.totalSeq = data['__total_seq']
+ self.mutex = data['__mutex']
+ self.nwaiters = data['__nwaiters']
+ self.values = []
+ self.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.readStatus()
+ self.readAttributes()
+ self.readMutexInfo()
+
+ def readStatus(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.totalSeq == PTHREAD_COND_DESTROYED:
+ self.values.append(('Status', 'Destroyed'))
+
+ self.values.append(('Threads waiting for this condvar',
+ self.nwaiters >> COND_NWAITERS_SHIFT))
+
+ def readAttributes(self):
+ """Read the condvar's attributes."""
+
+ clockID = self.nwaiters & ((1 << COND_NWAITERS_SHIFT) - 1)
+ shared = (self.mutex == PTHREAD_COND_SHARED)
+
+ if shared:
+ self.values.append(('Shared', 'Yes'))
+ else:
+ self.values.append(('Shared', 'No'))
+
+ self.values.append(('Clock ID', clockID))
+
+ def readMutexInfo(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 value of ~0l instead.
+ """
+
+ if self.mutex and self.mutex != PTHREAD_COND_SHARED:
+ mutexType = gdb.lookup_type('pthread_mutex_t')
+ mutex = self.mutex.cast(mutexType.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.
+ """
+
+ condattrStruct = gdb.lookup_type('struct pthread_condattr')
+ self.condattr = condattr.cast(condattrStruct)['value']
+ self.values = []
+ self.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.
+ """
+
+ clockID = self.condattr & ((1 << COND_NWAITERS_SHIFT) - 1)
+
+ if self.condattr & 1:
+ self.values.append(('Shared', 'Yes'))
+ else:
+ self.values.append(('Shared', 'No'))
+
+ self.values.append(('Clock ID', clockID))
+
+################################################################################
+
+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.queuedReaders = data['__nr_readers_queued']
+ self.queuedWriters = data['__nr_writers_queued']
+ self.writerID = data['__writer']
+ self.shared = data['__shared']
+ self.prefersWriters = data['__flags']
+ self.values = []
+ self.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.readStatus()
+ self.readAttributes()
+
+ def readStatus(self):
+ """Read the status of the rwlock."""
+
+ if self.writerID:
+ self.values.append(('Status', 'Locked (Write)'))
+ self.values.append(('Writer ID', self.writerID))
+ 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.queuedReaders))
+ self.values.append(('Queued writers', self.queuedWriters))
+
+ def readAttributes(self):
+ """Read the attributes of the rwlock."""
+
+ if self.shared:
+ self.values.append(('Shared', 'Yes'))
+ else:
+ self.values.append(('Shared', 'No'))
+
+ if self.prefersWriters:
+ 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.
+ """
+
+ rwlockattrStruct = gdb.lookup_type('struct pthread_rwlockattr')
+ self.rwlockattr = rwlockattr.cast(rwlockattrStruct)
+ self.values = []
+ self.readValues()
+
+ 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 Iterator(self.values)
+
+ def readValues(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.
+ """
+
+ rwlockType = 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 rwlockType == PTHREAD_RWLOCK_PREFER_READER_NP:
+ self.values.append(('Prefers', 'Readers'))
+ elif (rwlockType == PTHREAD_RWLOCK_PREFER_WRITER_NP or
+ rwlockType == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP):
+ self.values.append(('Prefers', 'Writers'))
+
+################################################################################
+
+class Printer(object):
+ """Printer class which conforms to the gdb pretty printing interface."""
+
+ def __init__(self, name):
+ self.name = name
+ self.enabled = True
+ self.subprinters = []
+
+ class Subprinter(object):
+ """A regex-based printer.
+
+ Individual pretty-printers are registered as subprinters of a single
+ Printer instance.
+ """
+
+ def __init__(self, name, regex, callable):
+ """
+ Initialize a pretty-printer.
+
+ Args:
+ name: The name of the printer.
+ regex: A regular expression. When gdb tries to print a variable
+ whose type matches the regex it'll trigger this printer.
+ callable: A function or callable object that gdb will call
+ when trying to print some value. It should return a
+ pretty-printer.
+ """
+ self.name = name
+ self.regex = re.compile(regex)
+ self.callable = callable
+ self.enabled = True
+
+ def addSubprinter(self, name, regex, callable):
+ """Register a regex-based subprinter."""
+
+ self.subprinters.append(self.Subprinter(name, regex, callable))
+
+ def __call__(self, value):
+ """gdb API function.
+
+ This is called when trying to print an inferior value
+ from gdb. If a registered printer's regex matches the value's type,
+ gdb will use the printer to print the value.
+ """
+
+ typeName = value.type.name
+
+ if typeName:
+ for subprinter in self.subprinters:
+ if subprinter.enabled and subprinter.regex.match(typeName):
+ return subprinter.callable(value)
+
+ # Return None if we have no type name or if we can't find a subprinter
+ # for the given type.
+ return None
+
+################################################################################
+
+def register(objfile):
+ """Register the pretty printers within the given objfile."""
+
+ printer = Printer('Glibc pthread locks')
+
+ printer.addSubprinter('pthread_mutex_t', '^pthread_mutex_t$', MutexPrinter)
+ printer.addSubprinter('pthread_mutexattr_t', '^pthread_mutexattr_t$',
+ MutexAttributesPrinter)
+ printer.addSubprinter('pthread_cond_t', '^pthread_cond_t$',
+ ConditionVariablePrinter)
+ printer.addSubprinter('pthread_condattr_t', '^pthread_condattr_t$',
+ ConditionVariableAttributesPrinter)
+ printer.addSubprinter('pthread_rwlock_t', '^pthread_rwlock_t$', RWLockPrinter)
+ printer.addSubprinter('pthread_rwlockattr_t', '^pthread_rwlockattr_t$',
+ RWLockAttributesPrinter)
+
+ gdb.printing.register_pretty_printer(objfile, printer)
+
+register(gdb.current_objfile())
new file mode 100644
@@ -0,0 +1,66 @@
+#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 ~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
+
+-- 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
new file mode 100644
@@ -0,0 +1,116 @@
+# Copyright (C) 2015 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Martin Galvan <martin.galvan@tallertechnologies.com>
+#
+# 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 script is a smaller version of the clever gen-asm-const.awk hack used to
+# generate ASM constants from .sym files. We'll use this to generate constants
+# for Python pretty-printers.
+#
+# The input to this script are .pysym files that look like:
+# #C_Preprocessor_Directive...
+# NAME1
+# NAME2 expression...
+#
+# A line giving just a name implies an expression consisting of just that name.
+# Comments start with '--'.
+#
+# The output of this script is a 'dummy' function containing 'asm' declarations
+# for each non-preprocessor line in the .pysym file. The expression values will
+# appear as input operands to the 'asm' declaration. For example, if we have:
+#
+# /* header.h */
+# #define MACRO 42
+#
+# struct S {
+# char c1;
+# char c2;
+# char c3;
+# };
+#
+# enum E {
+# ZERO,
+# ONE
+# };
+#
+# /* symbols.pysym */
+# #include <stddef.h>
+# #include "header.h"
+# -- This is a comment
+# MACRO
+# C3_OFFSET offsetof(struct S, c3)
+# E_ONE ONE
+#
+# the output will be:
+#
+# #include <stddef.h>
+# #include "header.h"
+# void dummy(void)
+# {
+# asm ("@name@MACRO@value@%0@" : : "i" (MACRO));
+# asm ("@name@C3_OFFSET@value@%0@" : : "i" (offsetof(struct S, c3)));
+# asm ("@name@E_ONE@value@%0@" : : "i" (ONE));
+# }
+#
+# We'll later feed this output to gcc -S. Since '-S' tells gcc to compile but
+# not assemble, gcc will output something like:
+#
+# dummy:
+# ...
+# @name@MACRO@value@$42@
+# @name@C3_OFFSET@value@$2@
+# @name@E_ONE@value@$1@
+#
+# Finally, we can process that output to extract the constant values.
+# Notice gcc will prepend a '$' to each value.
+
+# found_symbol indicates whether we found a non-comment, non-preprocessor line.
+BEGIN { found_symbol = 0 }
+
+# C preprocessor directives go straight through.
+/^#/ { print; next; }
+
+# Skip comments.
+/--/ { next; }
+
+# Trim leading whitespace.
+{ sub(/^[[:blank:]]*/, ""); }
+
+# If we found a non-comment, non-preprocessor line, print the 'dummy' function
+# header.
+NF > 0 && !found_symbol {
+ print "void dummy(void)\n{";
+ found_symbol = 1;
+}
+
+# If the line contains just a name, duplicate it so we can use that name
+# as the value of the expression.
+NF == 1 { sub(/^.*$/, "& &"); }
+
+# If a line contains a name and an expression...
+NF > 1 {
+ name = $1;
+
+ # Remove any characters before the second field.
+ sub(/^[^[:blank:]]+[[:blank:]]+/, "");
+
+ # '$0' ends up being everything that appeared after the first field
+ # separator.
+ printf " asm (\"@name@%s@value@%0@\" : : \"i\" (%s));\n", name, $0;
+}
+
+# Close the 'dummy' function.
+END { if (found_symbol) print "}"; }