diff options
Diffstat (limited to 'nptl/nptl-printers.py')
-rw-r--r-- | nptl/nptl-printers.py | 593 |
1 files changed, 0 insertions, 593 deletions
diff --git a/nptl/nptl-printers.py b/nptl/nptl-printers.py deleted file mode 100644 index f64216fb57..0000000000 --- a/nptl/nptl-printers.py +++ /dev/null @@ -1,593 +0,0 @@ -# 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 -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. - """ - - mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr') - self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind'] - self.values = [] - self.read_values() - - 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. - """ - - 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 == PTHREAD_COND_SHARED) - - 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 value of ~0l instead. - """ - - if self.mutex and self.mutex != PTHREAD_COND_SHARED: - 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. - """ - - condattr_struct = gdb.lookup_type('struct pthread_condattr') - self.condattr = condattr.cast(condattr_struct)['value'] - self.values = [] - self.read_values() - - 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. - """ - - rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr') - self.rwlockattr = rwlockattr.cast(rwlockattr_struct) - self.values = [] - self.read_values() - - 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) - - gdb.printing.register_pretty_printer(objfile, printer) - -register(gdb.current_objfile()) |