1 # Pretty printers for the NPTL lock types.
3 # Copyright (C) 2016-2018 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
39 # Constant definitions for pretty printers.
40 # See gen-py-const.awk for details.\n
41 PTHREAD_MUTEX_KIND_MASK = 3
42 PTHREAD_MUTEX_NORMAL = 0
43 PTHREAD_MUTEX_RECURSIVE = 1
44 PTHREAD_MUTEX_ERRORCHECK = 2
45 PTHREAD_MUTEX_ADAPTIVE_NP = 3
46 PTHREAD_MUTEX_DESTROYED = -1
47 PTHREAD_MUTEX_UNLOCKED = 0
48 PTHREAD_MUTEX_LOCKED_NO_WAITERS = 1
49 PTHREAD_MUTEX_INCONSISTENT = 2147483647
50 PTHREAD_MUTEX_NOTRECOVERABLE = 2147483646
51 FUTEX_OWNER_DIED = 1073741824
52 FUTEX_WAITERS = -2147483648
53 FUTEX_TID_MASK = 1073741823
54 PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16
55 PTHREAD_MUTEX_PRIO_INHERIT_NP = 32
56 PTHREAD_MUTEX_PRIO_PROTECT_NP = 64
57 PTHREAD_MUTEX_PSHARED_BIT = 128
58 PTHREAD_MUTEX_PRIO_CEILING_SHIFT = 19
59 PTHREAD_MUTEX_PRIO_CEILING_MASK = -524288
60 PTHREAD_MUTEXATTR_PROTOCOL_SHIFT = 28
61 PTHREAD_MUTEXATTR_PROTOCOL_MASK = 805306368
62 PTHREAD_MUTEXATTR_PRIO_CEILING_MASK = 16773120
63 PTHREAD_MUTEXATTR_FLAG_ROBUST = 1073741824
64 PTHREAD_MUTEXATTR_FLAG_PSHARED = -2147483648
65 PTHREAD_MUTEXATTR_FLAG_BITS = -251662336
66 PTHREAD_MUTEX_NO_ELISION_NP = 512
68 PTHREAD_PRIO_INHERIT = 1
69 PTHREAD_PRIO_PROTECT = 2
70 PTHREAD_COND_SHARED_MASK = 1
71 PTHREAD_COND_CLOCK_MONOTONIC_MASK = 2
73 PTHREAD_COND_WREFS_SHIFT = 3
74 PTHREAD_RWLOCK_PREFER_READER_NP = 0
75 PTHREAD_RWLOCK_PREFER_WRITER_NP = 1
76 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP = 2
77 PTHREAD_RWLOCK_WRPHASE = 1
78 PTHREAD_RWLOCK_WRLOCKED = 2
79 PTHREAD_RWLOCK_READER_SHIFT = 3
80 PTHREAD_PROCESS_PRIVATE = 0
81 PTHREAD_PROCESS_SHARED = 1
85 PTHREAD_MUTEX_NORMAL: ('Type', 'Normal'),
86 PTHREAD_MUTEX_RECURSIVE: ('Type', 'Recursive'),
87 PTHREAD_MUTEX_ERRORCHECK: ('Type', 'Error check'),
88 PTHREAD_MUTEX_ADAPTIVE_NP: ('Type', 'Adaptive')
91 class MutexPrinter(object):
92 """Pretty printer for pthread_mutex_t."""
94 def __init__(self, mutex):
95 """Initialize the printer's internal data structures.
98 mutex: A gdb.value representing a pthread_mutex_t.
101 data = mutex['__data']
102 self.lock = data['__lock']
103 self.count = data['__count']
104 self.owner = data['__owner']
105 self.kind = data['__kind']
112 This is called from gdb when we try to print a pthread_mutex_t.
115 return 'pthread_mutex_t'
120 This is called from gdb when we try to print a pthread_mutex_t.
125 def read_values(self):
126 """Read the mutex's info and store it in self.values.
128 The data contained in self.values will be returned by the Iterator
129 created in self.children.
134 self.read_attributes()
135 self.read_misc_info()
138 """Read the mutex's type."""
140 mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
142 # mutex_type must be casted to int because it's a gdb.Value
143 self.values.append(MUTEX_TYPES[int(mutex_type)])
145 def read_status(self):
146 """Read the mutex's status.
148 Architectures that support lock elision might not record the mutex owner
149 ID in the __owner field. In that case, the owner will be reported as
153 if self.kind == PTHREAD_MUTEX_DESTROYED:
154 self.values.append(('Status', 'Destroyed'))
155 elif self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
156 self.read_status_robust()
158 self.read_status_no_robust()
160 def read_status_robust(self):
161 """Read the status of a robust mutex.
163 In glibc robust mutexes are implemented in a very different way than
164 non-robust ones. This method reads their locking status,
165 whether it may have waiters, their registered owner (if any),
166 whether the owner is alive or not, and the status of the state
170 if self.lock == PTHREAD_MUTEX_UNLOCKED:
171 self.values.append(('Status', 'Not acquired'))
173 if self.lock & FUTEX_WAITERS:
174 self.values.append(('Status',
175 'Acquired, possibly with waiters'))
177 self.values.append(('Status',
178 'Acquired, possibly with no waiters'))
180 if self.lock & FUTEX_OWNER_DIED:
181 self.values.append(('Owner ID', '%d (dead)' % self.owner))
183 self.values.append(('Owner ID', self.lock & FUTEX_TID_MASK))
185 if self.owner == PTHREAD_MUTEX_INCONSISTENT:
186 self.values.append(('State protected by this mutex',
188 elif self.owner == PTHREAD_MUTEX_NOTRECOVERABLE:
189 self.values.append(('State protected by this mutex',
192 def read_status_no_robust(self):
193 """Read the status of a non-robust mutex.
195 Read info on whether the mutex is acquired, if it may have waiters
196 and its owner (if any).
199 lock_value = self.lock
201 if self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
202 lock_value &= ~(PTHREAD_MUTEX_PRIO_CEILING_MASK)
204 if lock_value == PTHREAD_MUTEX_UNLOCKED:
205 self.values.append(('Status', 'Not acquired'))
207 if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
208 waiters = self.lock & FUTEX_WAITERS
209 owner = self.lock & FUTEX_TID_MASK
211 # Mutex protocol is PP or none
212 waiters = (self.lock != PTHREAD_MUTEX_LOCKED_NO_WAITERS)
216 self.values.append(('Status',
217 'Acquired, possibly with waiters'))
219 self.values.append(('Status',
220 'Acquired, possibly with no waiters'))
223 self.values.append(('Owner ID', owner))
225 # Owner isn't recorded, probably because lock elision
227 self.values.append(('Owner ID', 'Unknown'))
229 def read_attributes(self):
230 """Read the mutex's attributes."""
232 if self.kind != PTHREAD_MUTEX_DESTROYED:
233 if self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
234 self.values.append(('Robust', 'Yes'))
236 self.values.append(('Robust', 'No'))
238 # In glibc, robust mutexes always have their pshared flag set to
239 # 'shared' regardless of what the pshared flag of their
240 # mutexattr was. Therefore a robust mutex will act as shared
241 # even if it was initialized with a 'private' mutexattr.
242 if self.kind & PTHREAD_MUTEX_PSHARED_BIT:
243 self.values.append(('Shared', 'Yes'))
245 self.values.append(('Shared', 'No'))
247 if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
248 self.values.append(('Protocol', 'Priority inherit'))
249 elif self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
250 prio_ceiling = ((self.lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
251 >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT)
253 self.values.append(('Protocol', 'Priority protect'))
254 self.values.append(('Priority ceiling', prio_ceiling))
257 self.values.append(('Protocol', 'None'))
259 def read_misc_info(self):
260 """Read miscellaneous info on the mutex.
262 For now this reads the number of times a recursive mutex was acquired
266 mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
268 if mutex_type == PTHREAD_MUTEX_RECURSIVE and self.count > 1:
269 self.values.append(('Times acquired by the owner', self.count))
271 class MutexAttributesPrinter(object):
272 """Pretty printer for pthread_mutexattr_t.
274 In the NPTL this is a type that's always casted to struct pthread_mutexattr
275 which has a single 'mutexkind' field containing the actual attributes.
278 def __init__(self, mutexattr):
279 """Initialize the printer's internal data structures.
282 mutexattr: A gdb.value representing a pthread_mutexattr_t.
288 mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr')
289 self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind']
292 # libpthread doesn't have debug symbols, thus we can't find the
293 # real struct type. Just print the union members.
294 self.values.append(('__size', mutexattr['__size']))
295 self.values.append(('__align', mutexattr['__align']))
300 This is called from gdb when we try to print a pthread_mutexattr_t.
303 return 'pthread_mutexattr_t'
308 This is called from gdb when we try to print a pthread_mutexattr_t.
313 def read_values(self):
314 """Read the mutexattr's info and store it in self.values.
316 The data contained in self.values will be returned by the Iterator
317 created in self.children.
320 mutexattr_type = (self.mutexattr
321 & ~PTHREAD_MUTEXATTR_FLAG_BITS
322 & ~PTHREAD_MUTEX_NO_ELISION_NP)
324 # mutexattr_type must be casted to int because it's a gdb.Value
325 self.values.append(MUTEX_TYPES[int(mutexattr_type)])
327 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_ROBUST:
328 self.values.append(('Robust', 'Yes'))
330 self.values.append(('Robust', 'No'))
332 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
333 self.values.append(('Shared', 'Yes'))
335 self.values.append(('Shared', 'No'))
337 protocol = ((self.mutexattr & PTHREAD_MUTEXATTR_PROTOCOL_MASK) >>
338 PTHREAD_MUTEXATTR_PROTOCOL_SHIFT)
340 if protocol == PTHREAD_PRIO_NONE:
341 self.values.append(('Protocol', 'None'))
342 elif protocol == PTHREAD_PRIO_INHERIT:
343 self.values.append(('Protocol', 'Priority inherit'))
344 elif protocol == PTHREAD_PRIO_PROTECT:
345 self.values.append(('Protocol', 'Priority protect'))
347 class ConditionVariablePrinter(object):
348 """Pretty printer for pthread_cond_t."""
350 def __init__(self, cond):
351 """Initialize the printer's internal data structures.
354 cond: A gdb.value representing a pthread_cond_t.
357 data = cond['__data']
358 self.wrefs = data['__wrefs']
366 This is called from gdb when we try to print a pthread_cond_t.
369 return 'pthread_cond_t'
374 This is called from gdb when we try to print a pthread_cond_t.
379 def read_values(self):
380 """Read the condvar's info and store it in self.values.
382 The data contained in self.values will be returned by the Iterator
383 created in self.children.
387 self.read_attributes()
389 def read_status(self):
390 """Read the status of the condvar.
392 This method reads whether the condvar is destroyed and how many threads
396 self.values.append(('Threads known to still execute a wait function',
397 self.wrefs >> PTHREAD_COND_WREFS_SHIFT))
399 def read_attributes(self):
400 """Read the condvar's attributes."""
402 if (self.wrefs & PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0:
403 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
405 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
407 if (self.wrefs & PTHREAD_COND_SHARED_MASK) != 0:
408 self.values.append(('Shared', 'Yes'))
410 self.values.append(('Shared', 'No'))
412 class ConditionVariableAttributesPrinter(object):
413 """Pretty printer for pthread_condattr_t.
415 In the NPTL this is a type that's always casted to struct pthread_condattr,
416 which has a single 'value' field containing the actual attributes.
419 def __init__(self, condattr):
420 """Initialize the printer's internal data structures.
423 condattr: A gdb.value representing a pthread_condattr_t.
429 condattr_struct = gdb.lookup_type('struct pthread_condattr')
430 self.condattr = condattr.cast(condattr_struct)['value']
433 # libpthread doesn't have debug symbols, thus we can't find the
434 # real struct type. Just print the union members.
435 self.values.append(('__size', condattr['__size']))
436 self.values.append(('__align', condattr['__align']))
441 This is called from gdb when we try to print a pthread_condattr_t.
444 return 'pthread_condattr_t'
449 This is called from gdb when we try to print a pthread_condattr_t.
454 def read_values(self):
455 """Read the condattr's info and store it in self.values.
457 The data contained in self.values will be returned by the Iterator
458 created in self.children.
461 clock_id = (self.condattr >> 1) & ((1 << COND_CLOCK_BITS) - 1)
464 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
466 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
468 if self.condattr & 1:
469 self.values.append(('Shared', 'Yes'))
471 self.values.append(('Shared', 'No'))
473 class RWLockPrinter(object):
474 """Pretty printer for pthread_rwlock_t."""
476 def __init__(self, rwlock):
477 """Initialize the printer's internal data structures.
480 rwlock: A gdb.value representing a pthread_rwlock_t.
483 data = rwlock['__data']
484 self.readers = data['__readers']
485 self.cur_writer = data['__cur_writer']
486 self.shared = data['__shared']
487 self.flags = data['__flags']
494 This is called from gdb when we try to print a pthread_rwlock_t.
497 return 'pthread_rwlock_t'
502 This is called from gdb when we try to print a pthread_rwlock_t.
507 def read_values(self):
508 """Read the rwlock's info and store it in self.values.
510 The data contained in self.values will be returned by the Iterator
511 created in self.children.
515 self.read_attributes()
517 def read_status(self):
518 """Read the status of the rwlock."""
520 if self.readers & PTHREAD_RWLOCK_WRPHASE:
521 if self.readers & PTHREAD_RWLOCK_WRLOCKED:
522 self.values.append(('Status', 'Acquired (Write)'))
523 self.values.append(('Writer ID', self.cur_writer))
525 self.values.append(('Status', 'Not acquired'))
527 r = self.readers >> PTHREAD_RWLOCK_READER_SHIFT
529 self.values.append(('Status', 'Acquired (Read)'))
530 self.values.append(('Readers', r))
532 self.values.append(('Status', 'Not acquired'))
534 def read_attributes(self):
535 """Read the attributes of the rwlock."""
538 self.values.append(('Shared', 'Yes'))
540 self.values.append(('Shared', 'No'))
542 if self.flags == PTHREAD_RWLOCK_PREFER_READER_NP:
543 self.values.append(('Prefers', 'Readers'))
544 elif self.flags == PTHREAD_RWLOCK_PREFER_WRITER_NP:
545 self.values.append(('Prefers', 'Writers'))
547 self.values.append(('Prefers', 'Writers no recursive readers'))
549 class RWLockAttributesPrinter(object):
550 """Pretty printer for pthread_rwlockattr_t.
552 In the NPTL this is a type that's always casted to
553 struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
554 containing the actual attributes.
557 def __init__(self, rwlockattr):
558 """Initialize the printer's internal data structures.
561 rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
567 rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
568 self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
571 # libpthread doesn't have debug symbols, thus we can't find the
572 # real struct type. Just print the union members.
573 self.values.append(('__size', rwlockattr['__size']))
574 self.values.append(('__align', rwlockattr['__align']))
579 This is called from gdb when we try to print a pthread_rwlockattr_t.
582 return 'pthread_rwlockattr_t'
587 This is called from gdb when we try to print a pthread_rwlockattr_t.
592 def read_values(self):
593 """Read the rwlockattr's info and store it in self.values.
595 The data contained in self.values will be returned by the Iterator
596 created in self.children.
599 rwlock_type = self.rwlockattr['lockkind']
600 shared = self.rwlockattr['pshared']
602 if shared == PTHREAD_PROCESS_SHARED:
603 self.values.append(('Shared', 'Yes'))
605 # PTHREAD_PROCESS_PRIVATE
606 self.values.append(('Shared', 'No'))
608 if rwlock_type == PTHREAD_RWLOCK_PREFER_READER_NP:
609 self.values.append(('Prefers', 'Readers'))
610 elif rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NP:
611 self.values.append(('Prefers', 'Writers'))
613 self.values.append(('Prefers', 'Writers no recursive readers'))
615 def register(objfile):
616 """Register the pretty printers within the given objfile."""
618 printer = gdb.printing.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
620 printer.add_printer('pthread_mutex_t', r'^pthread_mutex_t$',
622 printer.add_printer('pthread_mutexattr_t', r'^pthread_mutexattr_t$',
623 MutexAttributesPrinter)
624 printer.add_printer('pthread_cond_t', r'^pthread_cond_t$',
625 ConditionVariablePrinter)
626 printer.add_printer('pthread_condattr_t', r'^pthread_condattr_t$',
627 ConditionVariableAttributesPrinter)
628 printer.add_printer('pthread_rwlock_t', r'^pthread_rwlock_t$',
630 printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
631 RWLockAttributesPrinter)
636 gdb.printing.register_pretty_printer(objfile, printer)
638 register(gdb.current_objfile())