Update copyright dates with scripts/update-copyrights.
[glibc.git] / nptl / nptl-printers.py
blob17463c41e00dd29e25c81e24420dbcc5f5bb9da4
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:
22 * pthread_mutex_t
23 * pthread_mutexattr_t
24 * pthread_cond_t
25 * pthread_condattr_t
26 * pthread_rwlock_t
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.
32 """
34 from __future__ import print_function
36 import gdb
37 import gdb.printing
38 from nptl_lock_constants import *
40 MUTEX_TYPES = {
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.
53 Args:
54 mutex: A gdb.value representing a pthread_mutex_t.
55 """
57 data = mutex['__data']
58 self.lock = data['__lock']
59 self.count = data['__count']
60 self.owner = data['__owner']
61 self.kind = data['__kind']
62 self.values = []
63 self.read_values()
65 def to_string(self):
66 """gdb API function.
68 This is called from gdb when we try to print a pthread_mutex_t.
69 """
71 return 'pthread_mutex_t'
73 def children(self):
74 """gdb API function.
76 This is called from gdb when we try to print a pthread_mutex_t.
77 """
79 return self.values
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.
86 """
88 self.read_type()
89 self.read_status()
90 self.read_attributes()
91 self.read_misc_info()
93 def read_type(self):
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 For architectures which support lock elision, this method reads
105 whether the mutex appears as locked in memory (i.e. it may show it as
106 unlocked even after calling pthread_mutex_lock).
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()
113 else:
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
123 they're protecting.
126 if self.lock == PTHREAD_MUTEX_UNLOCKED:
127 self.values.append(('Status', 'Unlocked'))
128 else:
129 if self.lock & FUTEX_WAITERS:
130 self.values.append(('Status', 'Locked, possibly with waiters'))
131 else:
132 self.values.append(('Status',
133 'Locked, possibly with no waiters'))
135 if self.lock & FUTEX_OWNER_DIED:
136 self.values.append(('Owner ID', '%d (dead)' % self.owner))
137 else:
138 self.values.append(('Owner ID', self.lock & FUTEX_TID_MASK))
140 if self.owner == PTHREAD_MUTEX_INCONSISTENT:
141 self.values.append(('State protected by this mutex',
142 'Inconsistent'))
143 elif self.owner == PTHREAD_MUTEX_NOTRECOVERABLE:
144 self.values.append(('State protected by this mutex',
145 'Not recoverable'))
147 def read_status_no_robust(self):
148 """Read the status of a non-robust mutex.
150 Read info on whether the mutex is locked, if it may have waiters
151 and its owner (if any).
154 lock_value = self.lock
156 if self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
157 lock_value &= ~(PTHREAD_MUTEX_PRIO_CEILING_MASK)
159 if lock_value == PTHREAD_MUTEX_UNLOCKED:
160 self.values.append(('Status', 'Unlocked'))
161 else:
162 if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
163 waiters = self.lock & FUTEX_WAITERS
164 owner = self.lock & FUTEX_TID_MASK
165 else:
166 # Mutex protocol is PP or none
167 waiters = (self.lock != PTHREAD_MUTEX_LOCKED_NO_WAITERS)
168 owner = self.owner
170 if waiters:
171 self.values.append(('Status', 'Locked, possibly with waiters'))
172 else:
173 self.values.append(('Status',
174 'Locked, possibly with no waiters'))
176 self.values.append(('Owner ID', owner))
178 def read_attributes(self):
179 """Read the mutex's attributes."""
181 if self.kind != PTHREAD_MUTEX_DESTROYED:
182 if self.kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP:
183 self.values.append(('Robust', 'Yes'))
184 else:
185 self.values.append(('Robust', 'No'))
187 # In glibc, robust mutexes always have their pshared flag set to
188 # 'shared' regardless of what the pshared flag of their
189 # mutexattr was. Therefore a robust mutex will act as shared
190 # even if it was initialized with a 'private' mutexattr.
191 if self.kind & PTHREAD_MUTEX_PSHARED_BIT:
192 self.values.append(('Shared', 'Yes'))
193 else:
194 self.values.append(('Shared', 'No'))
196 if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
197 self.values.append(('Protocol', 'Priority inherit'))
198 elif self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
199 prio_ceiling = ((self.lock & PTHREAD_MUTEX_PRIO_CEILING_MASK)
200 >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT)
202 self.values.append(('Protocol', 'Priority protect'))
203 self.values.append(('Priority ceiling', prio_ceiling))
204 else:
205 # PTHREAD_PRIO_NONE
206 self.values.append(('Protocol', 'None'))
208 def read_misc_info(self):
209 """Read miscellaneous info on the mutex.
211 For now this reads the number of times a recursive mutex was locked
212 by the same thread.
215 mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
217 if mutex_type == PTHREAD_MUTEX_RECURSIVE and self.count > 1:
218 self.values.append(('Times locked recursively', self.count))
220 class MutexAttributesPrinter(object):
221 """Pretty printer for pthread_mutexattr_t.
223 In the NPTL this is a type that's always casted to struct pthread_mutexattr
224 which has a single 'mutexkind' field containing the actual attributes.
227 def __init__(self, mutexattr):
228 """Initialize the printer's internal data structures.
230 Args:
231 mutexattr: A gdb.value representing a pthread_mutexattr_t.
234 self.values = []
236 try:
237 mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr')
238 self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind']
239 self.read_values()
240 except gdb.error:
241 # libpthread doesn't have debug symbols, thus we can't find the
242 # real struct type. Just print the union members.
243 self.values.append(('__size', mutexattr['__size']))
244 self.values.append(('__align', mutexattr['__align']))
246 def to_string(self):
247 """gdb API function.
249 This is called from gdb when we try to print a pthread_mutexattr_t.
252 return 'pthread_mutexattr_t'
254 def children(self):
255 """gdb API function.
257 This is called from gdb when we try to print a pthread_mutexattr_t.
260 return self.values
262 def read_values(self):
263 """Read the mutexattr's info and store it in self.values.
265 The data contained in self.values will be returned by the Iterator
266 created in self.children.
269 mutexattr_type = (self.mutexattr
270 & ~PTHREAD_MUTEXATTR_FLAG_BITS
271 & ~PTHREAD_MUTEX_NO_ELISION_NP)
273 # mutexattr_type must be casted to int because it's a gdb.Value
274 self.values.append(MUTEX_TYPES[int(mutexattr_type)])
276 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_ROBUST:
277 self.values.append(('Robust', 'Yes'))
278 else:
279 self.values.append(('Robust', 'No'))
281 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
282 self.values.append(('Shared', 'Yes'))
283 else:
284 self.values.append(('Shared', 'No'))
286 protocol = ((self.mutexattr & PTHREAD_MUTEXATTR_PROTOCOL_MASK) >>
287 PTHREAD_MUTEXATTR_PROTOCOL_SHIFT)
289 if protocol == PTHREAD_PRIO_NONE:
290 self.values.append(('Protocol', 'None'))
291 elif protocol == PTHREAD_PRIO_INHERIT:
292 self.values.append(('Protocol', 'Priority inherit'))
293 elif protocol == PTHREAD_PRIO_PROTECT:
294 self.values.append(('Protocol', 'Priority protect'))
296 class ConditionVariablePrinter(object):
297 """Pretty printer for pthread_cond_t."""
299 def __init__(self, cond):
300 """Initialize the printer's internal data structures.
302 Args:
303 cond: A gdb.value representing a pthread_cond_t.
306 data = cond['__data']
307 self.wrefs = data['__wrefs']
308 self.values = []
310 self.read_values()
312 def to_string(self):
313 """gdb API function.
315 This is called from gdb when we try to print a pthread_cond_t.
318 return 'pthread_cond_t'
320 def children(self):
321 """gdb API function.
323 This is called from gdb when we try to print a pthread_cond_t.
326 return self.values
328 def read_values(self):
329 """Read the condvar's info and store it in self.values.
331 The data contained in self.values will be returned by the Iterator
332 created in self.children.
335 self.read_status()
336 self.read_attributes()
338 def read_status(self):
339 """Read the status of the condvar.
341 This method reads whether the condvar is destroyed and how many threads
342 are waiting for it.
345 self.values.append(('Threads known to still execute a wait function',
346 self.wrefs >> PTHREAD_COND_WREFS_SHIFT))
348 def read_attributes(self):
349 """Read the condvar's attributes."""
351 if (self.wrefs & PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0:
352 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
353 else:
354 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
356 if (self.wrefs & PTHREAD_COND_SHARED_MASK) != 0:
357 self.values.append(('Shared', 'Yes'))
358 else:
359 self.values.append(('Shared', 'No'))
361 class ConditionVariableAttributesPrinter(object):
362 """Pretty printer for pthread_condattr_t.
364 In the NPTL this is a type that's always casted to struct pthread_condattr,
365 which has a single 'value' field containing the actual attributes.
368 def __init__(self, condattr):
369 """Initialize the printer's internal data structures.
371 Args:
372 condattr: A gdb.value representing a pthread_condattr_t.
375 self.values = []
377 try:
378 condattr_struct = gdb.lookup_type('struct pthread_condattr')
379 self.condattr = condattr.cast(condattr_struct)['value']
380 self.read_values()
381 except gdb.error:
382 # libpthread doesn't have debug symbols, thus we can't find the
383 # real struct type. Just print the union members.
384 self.values.append(('__size', condattr['__size']))
385 self.values.append(('__align', condattr['__align']))
387 def to_string(self):
388 """gdb API function.
390 This is called from gdb when we try to print a pthread_condattr_t.
393 return 'pthread_condattr_t'
395 def children(self):
396 """gdb API function.
398 This is called from gdb when we try to print a pthread_condattr_t.
401 return self.values
403 def read_values(self):
404 """Read the condattr's info and store it in self.values.
406 The data contained in self.values will be returned by the Iterator
407 created in self.children.
410 clock_id = (self.condattr >> 1) & ((1 << COND_CLOCK_BITS) - 1)
412 if clock_id != 0:
413 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
414 else:
415 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
417 if self.condattr & 1:
418 self.values.append(('Shared', 'Yes'))
419 else:
420 self.values.append(('Shared', 'No'))
422 class RWLockPrinter(object):
423 """Pretty printer for pthread_rwlock_t."""
425 def __init__(self, rwlock):
426 """Initialize the printer's internal data structures.
428 Args:
429 rwlock: A gdb.value representing a pthread_rwlock_t.
432 data = rwlock['__data']
433 self.readers = data['__nr_readers']
434 self.queued_readers = data['__nr_readers_queued']
435 self.queued_writers = data['__nr_writers_queued']
436 self.writer_id = data['__writer']
437 self.shared = data['__shared']
438 self.prefers_writers = data['__flags']
439 self.values = []
440 self.read_values()
442 def to_string(self):
443 """gdb API function.
445 This is called from gdb when we try to print a pthread_rwlock_t.
448 return 'pthread_rwlock_t'
450 def children(self):
451 """gdb API function.
453 This is called from gdb when we try to print a pthread_rwlock_t.
456 return self.values
458 def read_values(self):
459 """Read the rwlock's info and store it in self.values.
461 The data contained in self.values will be returned by the Iterator
462 created in self.children.
465 self.read_status()
466 self.read_attributes()
468 def read_status(self):
469 """Read the status of the rwlock."""
471 # Right now pthread_rwlock_destroy doesn't do anything, so there's no
472 # way to check if an rwlock is destroyed.
474 if self.writer_id:
475 self.values.append(('Status', 'Locked (Write)'))
476 self.values.append(('Writer ID', self.writer_id))
477 elif self.readers:
478 self.values.append(('Status', 'Locked (Read)'))
479 self.values.append(('Readers', self.readers))
480 else:
481 self.values.append(('Status', 'Unlocked'))
483 self.values.append(('Queued readers', self.queued_readers))
484 self.values.append(('Queued writers', self.queued_writers))
486 def read_attributes(self):
487 """Read the attributes of the rwlock."""
489 if self.shared:
490 self.values.append(('Shared', 'Yes'))
491 else:
492 self.values.append(('Shared', 'No'))
494 if self.prefers_writers:
495 self.values.append(('Prefers', 'Writers'))
496 else:
497 self.values.append(('Prefers', 'Readers'))
499 class RWLockAttributesPrinter(object):
500 """Pretty printer for pthread_rwlockattr_t.
502 In the NPTL this is a type that's always casted to
503 struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
504 containing the actual attributes.
507 def __init__(self, rwlockattr):
508 """Initialize the printer's internal data structures.
510 Args:
511 rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
514 self.values = []
516 try:
517 rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
518 self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
519 self.read_values()
520 except gdb.error:
521 # libpthread doesn't have debug symbols, thus we can't find the
522 # real struct type. Just print the union members.
523 self.values.append(('__size', rwlockattr['__size']))
524 self.values.append(('__align', rwlockattr['__align']))
526 def to_string(self):
527 """gdb API function.
529 This is called from gdb when we try to print a pthread_rwlockattr_t.
532 return 'pthread_rwlockattr_t'
534 def children(self):
535 """gdb API function.
537 This is called from gdb when we try to print a pthread_rwlockattr_t.
540 return self.values
542 def read_values(self):
543 """Read the rwlockattr's info and store it in self.values.
545 The data contained in self.values will be returned by the Iterator
546 created in self.children.
549 rwlock_type = self.rwlockattr['lockkind']
550 shared = self.rwlockattr['pshared']
552 if shared == PTHREAD_PROCESS_SHARED:
553 self.values.append(('Shared', 'Yes'))
554 else:
555 # PTHREAD_PROCESS_PRIVATE
556 self.values.append(('Shared', 'No'))
558 if (rwlock_type == PTHREAD_RWLOCK_PREFER_READER_NP or
559 rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NP):
560 # This is a known bug. Using PTHREAD_RWLOCK_PREFER_WRITER_NP will
561 # still make the rwlock prefer readers.
562 self.values.append(('Prefers', 'Readers'))
563 elif rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP:
564 self.values.append(('Prefers', 'Writers'))
566 def register(objfile):
567 """Register the pretty printers within the given objfile."""
569 printer = gdb.printing.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
571 printer.add_printer('pthread_mutex_t', r'^pthread_mutex_t$',
572 MutexPrinter)
573 printer.add_printer('pthread_mutexattr_t', r'^pthread_mutexattr_t$',
574 MutexAttributesPrinter)
575 printer.add_printer('pthread_cond_t', r'^pthread_cond_t$',
576 ConditionVariablePrinter)
577 printer.add_printer('pthread_condattr_t', r'^pthread_condattr_t$',
578 ConditionVariableAttributesPrinter)
579 printer.add_printer('pthread_rwlock_t', r'^pthread_rwlock_t$',
580 RWLockPrinter)
581 printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
582 RWLockAttributesPrinter)
584 if objfile == None:
585 objfile = gdb
587 gdb.printing.register_pretty_printer(objfile, printer)
589 register(gdb.current_objfile())