Add build-many-glibcs.py arm-linux-gnueabihf-v7{-disable-multiarch}
[glibc.git] / nptl / nptl-printers.py
blob572a25c32eec3ae41496fb1d163a9a290f42ec4d
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 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
106 "Unknown".
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', 'Not acquired'))
128 else:
129 if self.lock & FUTEX_WAITERS:
130 self.values.append(('Status',
131 'Acquired, possibly with waiters'))
132 else:
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))
138 else:
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',
143 'Inconsistent'))
144 elif self.owner == PTHREAD_MUTEX_NOTRECOVERABLE:
145 self.values.append(('State protected by this mutex',
146 'Not recoverable'))
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'))
162 else:
163 if self.kind & PTHREAD_MUTEX_PRIO_INHERIT_NP:
164 waiters = self.lock & FUTEX_WAITERS
165 owner = self.lock & FUTEX_TID_MASK
166 else:
167 # Mutex protocol is PP or none
168 waiters = (self.lock != PTHREAD_MUTEX_LOCKED_NO_WAITERS)
169 owner = self.owner
171 if waiters:
172 self.values.append(('Status',
173 'Acquired, possibly with waiters'))
174 else:
175 self.values.append(('Status',
176 'Acquired, possibly with no waiters'))
178 if self.owner != 0:
179 self.values.append(('Owner ID', owner))
180 else:
181 # Owner isn't recorded, probably because lock elision
182 # is enabled.
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'))
191 else:
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'))
200 else:
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))
211 else:
212 # PTHREAD_PRIO_NONE
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
219 by the same thread.
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.
237 Args:
238 mutexattr: A gdb.value representing a pthread_mutexattr_t.
241 self.values = []
243 try:
244 mutexattr_struct = gdb.lookup_type('struct pthread_mutexattr')
245 self.mutexattr = mutexattr.cast(mutexattr_struct)['mutexkind']
246 self.read_values()
247 except gdb.error:
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']))
253 def to_string(self):
254 """gdb API function.
256 This is called from gdb when we try to print a pthread_mutexattr_t.
259 return 'pthread_mutexattr_t'
261 def children(self):
262 """gdb API function.
264 This is called from gdb when we try to print a pthread_mutexattr_t.
267 return self.values
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'))
285 else:
286 self.values.append(('Robust', 'No'))
288 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
289 self.values.append(('Shared', 'Yes'))
290 else:
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.
309 Args:
310 cond: A gdb.value representing a pthread_cond_t.
313 data = cond['__data']
314 self.wrefs = data['__wrefs']
315 self.values = []
317 self.read_values()
319 def to_string(self):
320 """gdb API function.
322 This is called from gdb when we try to print a pthread_cond_t.
325 return 'pthread_cond_t'
327 def children(self):
328 """gdb API function.
330 This is called from gdb when we try to print a pthread_cond_t.
333 return self.values
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.
342 self.read_status()
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
349 are waiting for it.
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'))
360 else:
361 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
363 if (self.wrefs & PTHREAD_COND_SHARED_MASK) != 0:
364 self.values.append(('Shared', 'Yes'))
365 else:
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.
378 Args:
379 condattr: A gdb.value representing a pthread_condattr_t.
382 self.values = []
384 try:
385 condattr_struct = gdb.lookup_type('struct pthread_condattr')
386 self.condattr = condattr.cast(condattr_struct)['value']
387 self.read_values()
388 except gdb.error:
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']))
394 def to_string(self):
395 """gdb API function.
397 This is called from gdb when we try to print a pthread_condattr_t.
400 return 'pthread_condattr_t'
402 def children(self):
403 """gdb API function.
405 This is called from gdb when we try to print a pthread_condattr_t.
408 return self.values
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)
419 if clock_id != 0:
420 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
421 else:
422 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
424 if self.condattr & 1:
425 self.values.append(('Shared', 'Yes'))
426 else:
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.
435 Args:
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']
444 self.values = []
445 self.read_values()
447 def to_string(self):
448 """gdb API function.
450 This is called from gdb when we try to print a pthread_rwlock_t.
453 return 'pthread_rwlock_t'
455 def children(self):
456 """gdb API function.
458 This is called from gdb when we try to print a pthread_rwlock_t.
461 return self.values
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.
470 self.read_status()
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))
480 else:
481 self.values.append(('Status', 'Not acquired'))
482 else:
483 r = self.readers >> PTHREAD_RWLOCK_READER_SHIFT
484 if r > 0:
485 self.values.append(('Status', 'Acquired (Read)'))
486 self.values.append(('Readers', r))
487 else:
488 self.values.append(('Status', 'Not acquired'))
490 def read_attributes(self):
491 """Read the attributes of the rwlock."""
493 if self.shared:
494 self.values.append(('Shared', 'Yes'))
495 else:
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'))
502 else:
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.
516 Args:
517 rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
520 self.values = []
522 try:
523 rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
524 self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
525 self.read_values()
526 except gdb.error:
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']))
532 def to_string(self):
533 """gdb API function.
535 This is called from gdb when we try to print a pthread_rwlockattr_t.
538 return 'pthread_rwlockattr_t'
540 def children(self):
541 """gdb API function.
543 This is called from gdb when we try to print a pthread_rwlockattr_t.
546 return self.values
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'))
560 else:
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'))
568 else:
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$',
577 MutexPrinter)
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$',
585 RWLockPrinter)
586 printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
587 RWLockAttributesPrinter)
589 if objfile == None:
590 objfile = gdb
592 gdb.printing.register_pretty_printer(objfile, printer)
594 register(gdb.current_objfile())