1 # Pretty printers for the NPTL lock types.
3 # Copyright (C) 2016-2017 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <http://www.gnu.org/licenses/>.
20 """This file contains the gdb pretty printers for the following types:
27 * pthread_rwlockattr_t
29 You can check which printers are registered and enabled by issuing the
30 'info pretty-printer' gdb command. Printers should trigger automatically when
31 trying to print a variable of one of the types mentioned above.
34 from __future__
import print_function
38 from nptl_lock_constants
import *
41 PTHREAD_MUTEX_NORMAL
: ('Type', 'Normal'),
42 PTHREAD_MUTEX_RECURSIVE
: ('Type', 'Recursive'),
43 PTHREAD_MUTEX_ERRORCHECK
: ('Type', 'Error check'),
44 PTHREAD_MUTEX_ADAPTIVE_NP
: ('Type', 'Adaptive')
47 class MutexPrinter(object):
48 """Pretty printer for pthread_mutex_t."""
50 def __init__(self
, mutex
):
51 """Initialize the printer's internal data structures.
54 mutex: A gdb.value representing a pthread_mutex_t.
57 data
= mutex
['__data']
58 self
.lock
= data
['__lock']
59 self
.count
= data
['__count']
60 self
.owner
= data
['__owner']
61 self
.kind
= data
['__kind']
68 This is called from gdb when we try to print a pthread_mutex_t.
71 return 'pthread_mutex_t'
76 This is called from gdb when we try to print a pthread_mutex_t.
81 def read_values(self
):
82 """Read the mutex's info and store it in self.values.
84 The data contained in self.values will be returned by the Iterator
85 created in self.children.
90 self
.read_attributes()
94 """Read the mutex's type."""
96 mutex_type
= self
.kind
& PTHREAD_MUTEX_KIND_MASK
98 # mutex_type must be casted to int because it's a gdb.Value
99 self
.values
.append(MUTEX_TYPES
[int(mutex_type
)])
101 def read_status(self
):
102 """Read the mutex's status.
104 Architectures that support lock elision might not record the mutex owner
105 ID in the __owner field. In that case, the owner will be reported as
109 if self
.kind
== PTHREAD_MUTEX_DESTROYED
:
110 self
.values
.append(('Status', 'Destroyed'))
111 elif self
.kind
& PTHREAD_MUTEX_ROBUST_NORMAL_NP
:
112 self
.read_status_robust()
114 self
.read_status_no_robust()
116 def read_status_robust(self
):
117 """Read the status of a robust mutex.
119 In glibc robust mutexes are implemented in a very different way than
120 non-robust ones. This method reads their locking status,
121 whether it may have waiters, their registered owner (if any),
122 whether the owner is alive or not, and the status of the state
126 if self
.lock
== PTHREAD_MUTEX_UNLOCKED
:
127 self
.values
.append(('Status', 'Not acquired'))
129 if self
.lock
& FUTEX_WAITERS
:
130 self
.values
.append(('Status',
131 'Acquired, possibly with waiters'))
133 self
.values
.append(('Status',
134 'Acquired, possibly with no waiters'))
136 if self
.lock
& FUTEX_OWNER_DIED
:
137 self
.values
.append(('Owner ID', '%d (dead)' % self
.owner
))
139 self
.values
.append(('Owner ID', self
.lock
& FUTEX_TID_MASK
))
141 if self
.owner
== PTHREAD_MUTEX_INCONSISTENT
:
142 self
.values
.append(('State protected by this mutex',
144 elif self
.owner
== PTHREAD_MUTEX_NOTRECOVERABLE
:
145 self
.values
.append(('State protected by this mutex',
148 def read_status_no_robust(self
):
149 """Read the status of a non-robust mutex.
151 Read info on whether the mutex is acquired, if it may have waiters
152 and its owner (if any).
155 lock_value
= self
.lock
157 if self
.kind
& PTHREAD_MUTEX_PRIO_PROTECT_NP
:
158 lock_value
&= ~
(PTHREAD_MUTEX_PRIO_CEILING_MASK
)
160 if lock_value
== PTHREAD_MUTEX_UNLOCKED
:
161 self
.values
.append(('Status', 'Not acquired'))
163 if self
.kind
& PTHREAD_MUTEX_PRIO_INHERIT_NP
:
164 waiters
= self
.lock
& FUTEX_WAITERS
165 owner
= self
.lock
& FUTEX_TID_MASK
167 # Mutex protocol is PP or none
168 waiters
= (self
.lock
!= PTHREAD_MUTEX_LOCKED_NO_WAITERS
)
172 self
.values
.append(('Status',
173 'Acquired, possibly with waiters'))
175 self
.values
.append(('Status',
176 'Acquired, possibly with no waiters'))
179 self
.values
.append(('Owner ID', owner
))
181 # Owner isn't recorded, probably because lock elision
183 self
.values
.append(('Owner ID', 'Unknown'))
185 def read_attributes(self
):
186 """Read the mutex's attributes."""
188 if self
.kind
!= PTHREAD_MUTEX_DESTROYED
:
189 if self
.kind
& PTHREAD_MUTEX_ROBUST_NORMAL_NP
:
190 self
.values
.append(('Robust', 'Yes'))
192 self
.values
.append(('Robust', 'No'))
194 # In glibc, robust mutexes always have their pshared flag set to
195 # 'shared' regardless of what the pshared flag of their
196 # mutexattr was. Therefore a robust mutex will act as shared
197 # even if it was initialized with a 'private' mutexattr.
198 if self
.kind
& PTHREAD_MUTEX_PSHARED_BIT
:
199 self
.values
.append(('Shared', 'Yes'))
201 self
.values
.append(('Shared', 'No'))
203 if self
.kind
& PTHREAD_MUTEX_PRIO_INHERIT_NP
:
204 self
.values
.append(('Protocol', 'Priority inherit'))
205 elif self
.kind
& PTHREAD_MUTEX_PRIO_PROTECT_NP
:
206 prio_ceiling
= ((self
.lock
& PTHREAD_MUTEX_PRIO_CEILING_MASK
)
207 >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT
)
209 self
.values
.append(('Protocol', 'Priority protect'))
210 self
.values
.append(('Priority ceiling', prio_ceiling
))
213 self
.values
.append(('Protocol', 'None'))
215 def read_misc_info(self
):
216 """Read miscellaneous info on the mutex.
218 For now this reads the number of times a recursive mutex was acquired
222 mutex_type
= self
.kind
& PTHREAD_MUTEX_KIND_MASK
224 if mutex_type
== PTHREAD_MUTEX_RECURSIVE
and self
.count
> 1:
225 self
.values
.append(('Times acquired by the owner', self
.count
))
227 class MutexAttributesPrinter(object):
228 """Pretty printer for pthread_mutexattr_t.
230 In the NPTL this is a type that's always casted to struct pthread_mutexattr
231 which has a single 'mutexkind' field containing the actual attributes.
234 def __init__(self
, mutexattr
):
235 """Initialize the printer's internal data structures.
238 mutexattr: A gdb.value representing a pthread_mutexattr_t.
244 mutexattr_struct
= gdb
.lookup_type('struct pthread_mutexattr')
245 self
.mutexattr
= mutexattr
.cast(mutexattr_struct
)['mutexkind']
248 # libpthread doesn't have debug symbols, thus we can't find the
249 # real struct type. Just print the union members.
250 self
.values
.append(('__size', mutexattr
['__size']))
251 self
.values
.append(('__align', mutexattr
['__align']))
256 This is called from gdb when we try to print a pthread_mutexattr_t.
259 return 'pthread_mutexattr_t'
264 This is called from gdb when we try to print a pthread_mutexattr_t.
269 def read_values(self
):
270 """Read the mutexattr's info and store it in self.values.
272 The data contained in self.values will be returned by the Iterator
273 created in self.children.
276 mutexattr_type
= (self
.mutexattr
277 & ~PTHREAD_MUTEXATTR_FLAG_BITS
278 & ~PTHREAD_MUTEX_NO_ELISION_NP
)
280 # mutexattr_type must be casted to int because it's a gdb.Value
281 self
.values
.append(MUTEX_TYPES
[int(mutexattr_type
)])
283 if self
.mutexattr
& PTHREAD_MUTEXATTR_FLAG_ROBUST
:
284 self
.values
.append(('Robust', 'Yes'))
286 self
.values
.append(('Robust', 'No'))
288 if self
.mutexattr
& PTHREAD_MUTEXATTR_FLAG_PSHARED
:
289 self
.values
.append(('Shared', 'Yes'))
291 self
.values
.append(('Shared', 'No'))
293 protocol
= ((self
.mutexattr
& PTHREAD_MUTEXATTR_PROTOCOL_MASK
) >>
294 PTHREAD_MUTEXATTR_PROTOCOL_SHIFT
)
296 if protocol
== PTHREAD_PRIO_NONE
:
297 self
.values
.append(('Protocol', 'None'))
298 elif protocol
== PTHREAD_PRIO_INHERIT
:
299 self
.values
.append(('Protocol', 'Priority inherit'))
300 elif protocol
== PTHREAD_PRIO_PROTECT
:
301 self
.values
.append(('Protocol', 'Priority protect'))
303 class ConditionVariablePrinter(object):
304 """Pretty printer for pthread_cond_t."""
306 def __init__(self
, cond
):
307 """Initialize the printer's internal data structures.
310 cond: A gdb.value representing a pthread_cond_t.
313 data
= cond
['__data']
314 self
.wrefs
= data
['__wrefs']
322 This is called from gdb when we try to print a pthread_cond_t.
325 return 'pthread_cond_t'
330 This is called from gdb when we try to print a pthread_cond_t.
335 def read_values(self
):
336 """Read the condvar's info and store it in self.values.
338 The data contained in self.values will be returned by the Iterator
339 created in self.children.
343 self
.read_attributes()
345 def read_status(self
):
346 """Read the status of the condvar.
348 This method reads whether the condvar is destroyed and how many threads
352 self
.values
.append(('Threads known to still execute a wait function',
353 self
.wrefs
>> PTHREAD_COND_WREFS_SHIFT
))
355 def read_attributes(self
):
356 """Read the condvar's attributes."""
358 if (self
.wrefs
& PTHREAD_COND_CLOCK_MONOTONIC_MASK
) != 0:
359 self
.values
.append(('Clock ID', 'CLOCK_MONOTONIC'))
361 self
.values
.append(('Clock ID', 'CLOCK_REALTIME'))
363 if (self
.wrefs
& PTHREAD_COND_SHARED_MASK
) != 0:
364 self
.values
.append(('Shared', 'Yes'))
366 self
.values
.append(('Shared', 'No'))
368 class ConditionVariableAttributesPrinter(object):
369 """Pretty printer for pthread_condattr_t.
371 In the NPTL this is a type that's always casted to struct pthread_condattr,
372 which has a single 'value' field containing the actual attributes.
375 def __init__(self
, condattr
):
376 """Initialize the printer's internal data structures.
379 condattr: A gdb.value representing a pthread_condattr_t.
385 condattr_struct
= gdb
.lookup_type('struct pthread_condattr')
386 self
.condattr
= condattr
.cast(condattr_struct
)['value']
389 # libpthread doesn't have debug symbols, thus we can't find the
390 # real struct type. Just print the union members.
391 self
.values
.append(('__size', condattr
['__size']))
392 self
.values
.append(('__align', condattr
['__align']))
397 This is called from gdb when we try to print a pthread_condattr_t.
400 return 'pthread_condattr_t'
405 This is called from gdb when we try to print a pthread_condattr_t.
410 def read_values(self
):
411 """Read the condattr's info and store it in self.values.
413 The data contained in self.values will be returned by the Iterator
414 created in self.children.
417 clock_id
= (self
.condattr
>> 1) & ((1 << COND_CLOCK_BITS
) - 1)
420 self
.values
.append(('Clock ID', 'CLOCK_MONOTONIC'))
422 self
.values
.append(('Clock ID', 'CLOCK_REALTIME'))
424 if self
.condattr
& 1:
425 self
.values
.append(('Shared', 'Yes'))
427 self
.values
.append(('Shared', 'No'))
429 class RWLockPrinter(object):
430 """Pretty printer for pthread_rwlock_t."""
432 def __init__(self
, rwlock
):
433 """Initialize the printer's internal data structures.
436 rwlock: A gdb.value representing a pthread_rwlock_t.
439 data
= rwlock
['__data']
440 self
.readers
= data
['__readers']
441 self
.cur_writer
= data
['__cur_writer']
442 self
.shared
= data
['__shared']
443 self
.flags
= data
['__flags']
450 This is called from gdb when we try to print a pthread_rwlock_t.
453 return 'pthread_rwlock_t'
458 This is called from gdb when we try to print a pthread_rwlock_t.
463 def read_values(self
):
464 """Read the rwlock's info and store it in self.values.
466 The data contained in self.values will be returned by the Iterator
467 created in self.children.
471 self
.read_attributes()
473 def read_status(self
):
474 """Read the status of the rwlock."""
476 if self
.readers
& PTHREAD_RWLOCK_WRPHASE
:
477 if self
.readers
& PTHREAD_RWLOCK_WRLOCKED
:
478 self
.values
.append(('Status', 'Acquired (Write)'))
479 self
.values
.append(('Writer ID', self
.cur_writer
))
481 self
.values
.append(('Status', 'Not acquired'))
483 r
= self
.readers
>> PTHREAD_RWLOCK_READER_SHIFT
485 self
.values
.append(('Status', 'Acquired (Read)'))
486 self
.values
.append(('Readers', r
))
488 self
.values
.append(('Status', 'Not acquired'))
490 def read_attributes(self
):
491 """Read the attributes of the rwlock."""
494 self
.values
.append(('Shared', 'Yes'))
496 self
.values
.append(('Shared', 'No'))
498 if self
.flags
== PTHREAD_RWLOCK_PREFER_READER_NP
:
499 self
.values
.append(('Prefers', 'Readers'))
500 elif self
.flags
== PTHREAD_RWLOCK_PREFER_WRITER_NP
:
501 self
.values
.append(('Prefers', 'Writers'))
503 self
.values
.append(('Prefers', 'Writers no recursive readers'))
505 class RWLockAttributesPrinter(object):
506 """Pretty printer for pthread_rwlockattr_t.
508 In the NPTL this is a type that's always casted to
509 struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
510 containing the actual attributes.
513 def __init__(self
, rwlockattr
):
514 """Initialize the printer's internal data structures.
517 rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
523 rwlockattr_struct
= gdb
.lookup_type('struct pthread_rwlockattr')
524 self
.rwlockattr
= rwlockattr
.cast(rwlockattr_struct
)
527 # libpthread doesn't have debug symbols, thus we can't find the
528 # real struct type. Just print the union members.
529 self
.values
.append(('__size', rwlockattr
['__size']))
530 self
.values
.append(('__align', rwlockattr
['__align']))
535 This is called from gdb when we try to print a pthread_rwlockattr_t.
538 return 'pthread_rwlockattr_t'
543 This is called from gdb when we try to print a pthread_rwlockattr_t.
548 def read_values(self
):
549 """Read the rwlockattr's info and store it in self.values.
551 The data contained in self.values will be returned by the Iterator
552 created in self.children.
555 rwlock_type
= self
.rwlockattr
['lockkind']
556 shared
= self
.rwlockattr
['pshared']
558 if shared
== PTHREAD_PROCESS_SHARED
:
559 self
.values
.append(('Shared', 'Yes'))
561 # PTHREAD_PROCESS_PRIVATE
562 self
.values
.append(('Shared', 'No'))
564 if rwlock_type
== PTHREAD_RWLOCK_PREFER_READER_NP
:
565 self
.values
.append(('Prefers', 'Readers'))
566 elif rwlock_type
== PTHREAD_RWLOCK_PREFER_WRITER_NP
:
567 self
.values
.append(('Prefers', 'Writers'))
569 self
.values
.append(('Prefers', 'Writers no recursive readers'))
571 def register(objfile
):
572 """Register the pretty printers within the given objfile."""
574 printer
= gdb
.printing
.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
576 printer
.add_printer('pthread_mutex_t', r
'^pthread_mutex_t$',
578 printer
.add_printer('pthread_mutexattr_t', r
'^pthread_mutexattr_t$',
579 MutexAttributesPrinter
)
580 printer
.add_printer('pthread_cond_t', r
'^pthread_cond_t$',
581 ConditionVariablePrinter
)
582 printer
.add_printer('pthread_condattr_t', r
'^pthread_condattr_t$',
583 ConditionVariableAttributesPrinter
)
584 printer
.add_printer('pthread_rwlock_t', r
'^pthread_rwlock_t$',
586 printer
.add_printer('pthread_rwlockattr_t', r
'^pthread_rwlockattr_t$',
587 RWLockAttributesPrinter
)
592 gdb
.printing
.register_pretty_printer(objfile
, printer
)
594 register(gdb
.current_objfile())