]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/nptl-printers.py
Regenerate charmap-kw.h, locfile-kw.h
[thirdparty/glibc.git] / nptl / nptl-printers.py
CommitLineData
23b5cae1
MG
1# Pretty printers for the NPTL lock types.
2#
04277e02 3# Copyright (C) 2016-2019 Free Software Foundation, Inc.
23b5cae1
MG
4# This file is part of the GNU C Library.
5#
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.
10#
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.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with the GNU C Library; if not, see
5a82c748 18# <https://www.gnu.org/licenses/>.
23b5cae1
MG
19
20"""This file contains the gdb pretty printers for the following types:
21
22 * pthread_mutex_t
23 * pthread_mutexattr_t
24 * pthread_cond_t
25 * pthread_condattr_t
26 * pthread_rwlock_t
27 * pthread_rwlockattr_t
28
29You can check which printers are registered and enabled by issuing the
30'info pretty-printer' gdb command. Printers should trigger automatically when
31trying to print a variable of one of the types mentioned above.
32"""
33
34from __future__ import print_function
35
36import gdb
37import gdb.printing
38from nptl_lock_constants import *
39
40MUTEX_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')
45}
46
47class MutexPrinter(object):
48 """Pretty printer for pthread_mutex_t."""
49
50 def __init__(self, mutex):
51 """Initialize the printer's internal data structures.
52
53 Args:
54 mutex: A gdb.value representing a pthread_mutex_t.
55 """
56
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()
64
65 def to_string(self):
66 """gdb API function.
67
68 This is called from gdb when we try to print a pthread_mutex_t.
69 """
70
71 return 'pthread_mutex_t'
72
73 def children(self):
74 """gdb API function.
75
76 This is called from gdb when we try to print a pthread_mutex_t.
77 """
78
79 return self.values
80
81 def read_values(self):
82 """Read the mutex's info and store it in self.values.
83
84 The data contained in self.values will be returned by the Iterator
85 created in self.children.
86 """
87
88 self.read_type()
89 self.read_status()
90 self.read_attributes()
91 self.read_misc_info()
92
93 def read_type(self):
94 """Read the mutex's type."""
95
96 mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
97
98 # mutex_type must be casted to int because it's a gdb.Value
99 self.values.append(MUTEX_TYPES[int(mutex_type)])
100
101 def read_status(self):
102 """Read the mutex's status.
103
6d523660
TR
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".
23b5cae1
MG
107 """
108
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()
115
116 def read_status_robust(self):
117 """Read the status of a robust mutex.
118
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.
124 """
125
126 if self.lock == PTHREAD_MUTEX_UNLOCKED:
6d523660 127 self.values.append(('Status', 'Not acquired'))
23b5cae1
MG
128 else:
129 if self.lock & FUTEX_WAITERS:
6d523660
TR
130 self.values.append(('Status',
131 'Acquired, possibly with waiters'))
23b5cae1
MG
132 else:
133 self.values.append(('Status',
6d523660 134 'Acquired, possibly with no waiters'))
23b5cae1
MG
135
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))
140
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'))
147
148 def read_status_no_robust(self):
149 """Read the status of a non-robust mutex.
150
6d523660 151 Read info on whether the mutex is acquired, if it may have waiters
23b5cae1
MG
152 and its owner (if any).
153 """
154
155 lock_value = self.lock
156
157 if self.kind & PTHREAD_MUTEX_PRIO_PROTECT_NP:
cb7be159 158 lock_value &= 0xffffffff & ~(PTHREAD_MUTEX_PRIO_CEILING_MASK)
23b5cae1
MG
159
160 if lock_value == PTHREAD_MUTEX_UNLOCKED:
6d523660 161 self.values.append(('Status', 'Not acquired'))
23b5cae1
MG
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
170
171 if waiters:
6d523660
TR
172 self.values.append(('Status',
173 'Acquired, possibly with waiters'))
23b5cae1
MG
174 else:
175 self.values.append(('Status',
6d523660 176 'Acquired, possibly with no waiters'))
23b5cae1 177
6d523660
TR
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'))
23b5cae1
MG
184
185 def read_attributes(self):
186 """Read the mutex's attributes."""
187
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'))
193
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'))
202
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)
208
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'))
214
215 def read_misc_info(self):
216 """Read miscellaneous info on the mutex.
217
6d523660 218 For now this reads the number of times a recursive mutex was acquired
23b5cae1
MG
219 by the same thread.
220 """
221
222 mutex_type = self.kind & PTHREAD_MUTEX_KIND_MASK
223
224 if mutex_type == PTHREAD_MUTEX_RECURSIVE and self.count > 1:
6d523660 225 self.values.append(('Times acquired by the owner', self.count))
23b5cae1
MG
226
227class MutexAttributesPrinter(object):
228 """Pretty printer for pthread_mutexattr_t.
229
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.
232 """
233
234 def __init__(self, mutexattr):
235 """Initialize the printer's internal data structures.
236
237 Args:
238 mutexattr: A gdb.value representing a pthread_mutexattr_t.
239 """
240
241 self.values = []
242
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']))
252
253 def to_string(self):
254 """gdb API function.
255
256 This is called from gdb when we try to print a pthread_mutexattr_t.
257 """
258
259 return 'pthread_mutexattr_t'
260
261 def children(self):
262 """gdb API function.
263
264 This is called from gdb when we try to print a pthread_mutexattr_t.
265 """
266
267 return self.values
268
269 def read_values(self):
270 """Read the mutexattr's info and store it in self.values.
271
272 The data contained in self.values will be returned by the Iterator
273 created in self.children.
274 """
275
276 mutexattr_type = (self.mutexattr
cb7be159 277 & 0xffffffff
23b5cae1
MG
278 & ~PTHREAD_MUTEXATTR_FLAG_BITS
279 & ~PTHREAD_MUTEX_NO_ELISION_NP)
280
281 # mutexattr_type must be casted to int because it's a gdb.Value
282 self.values.append(MUTEX_TYPES[int(mutexattr_type)])
283
284 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_ROBUST:
285 self.values.append(('Robust', 'Yes'))
286 else:
287 self.values.append(('Robust', 'No'))
288
289 if self.mutexattr & PTHREAD_MUTEXATTR_FLAG_PSHARED:
290 self.values.append(('Shared', 'Yes'))
291 else:
292 self.values.append(('Shared', 'No'))
293
294 protocol = ((self.mutexattr & PTHREAD_MUTEXATTR_PROTOCOL_MASK) >>
295 PTHREAD_MUTEXATTR_PROTOCOL_SHIFT)
296
297 if protocol == PTHREAD_PRIO_NONE:
298 self.values.append(('Protocol', 'None'))
299 elif protocol == PTHREAD_PRIO_INHERIT:
300 self.values.append(('Protocol', 'Priority inherit'))
301 elif protocol == PTHREAD_PRIO_PROTECT:
302 self.values.append(('Protocol', 'Priority protect'))
303
23b5cae1
MG
304class ConditionVariablePrinter(object):
305 """Pretty printer for pthread_cond_t."""
306
307 def __init__(self, cond):
308 """Initialize the printer's internal data structures.
309
310 Args:
311 cond: A gdb.value representing a pthread_cond_t.
312 """
313
23b5cae1 314 data = cond['__data']
ed19993b 315 self.wrefs = data['__wrefs']
23b5cae1
MG
316 self.values = []
317
318 self.read_values()
319
320 def to_string(self):
321 """gdb API function.
322
323 This is called from gdb when we try to print a pthread_cond_t.
324 """
325
326 return 'pthread_cond_t'
327
328 def children(self):
329 """gdb API function.
330
331 This is called from gdb when we try to print a pthread_cond_t.
332 """
333
334 return self.values
335
336 def read_values(self):
337 """Read the condvar's info and store it in self.values.
338
339 The data contained in self.values will be returned by the Iterator
340 created in self.children.
341 """
342
343 self.read_status()
344 self.read_attributes()
23b5cae1
MG
345
346 def read_status(self):
347 """Read the status of the condvar.
348
349 This method reads whether the condvar is destroyed and how many threads
350 are waiting for it.
351 """
352
ed19993b
TR
353 self.values.append(('Threads known to still execute a wait function',
354 self.wrefs >> PTHREAD_COND_WREFS_SHIFT))
23b5cae1
MG
355
356 def read_attributes(self):
357 """Read the condvar's attributes."""
358
26e21ad3
MG
359 if (self.wrefs & PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0:
360 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
361 else:
362 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
23b5cae1 363
ed19993b 364 if (self.wrefs & PTHREAD_COND_SHARED_MASK) != 0:
23b5cae1
MG
365 self.values.append(('Shared', 'Yes'))
366 else:
367 self.values.append(('Shared', 'No'))
368
23b5cae1
MG
369class ConditionVariableAttributesPrinter(object):
370 """Pretty printer for pthread_condattr_t.
371
372 In the NPTL this is a type that's always casted to struct pthread_condattr,
373 which has a single 'value' field containing the actual attributes.
374 """
375
376 def __init__(self, condattr):
377 """Initialize the printer's internal data structures.
378
379 Args:
380 condattr: A gdb.value representing a pthread_condattr_t.
381 """
382
383 self.values = []
384
385 try:
386 condattr_struct = gdb.lookup_type('struct pthread_condattr')
387 self.condattr = condattr.cast(condattr_struct)['value']
388 self.read_values()
389 except gdb.error:
390 # libpthread doesn't have debug symbols, thus we can't find the
391 # real struct type. Just print the union members.
392 self.values.append(('__size', condattr['__size']))
393 self.values.append(('__align', condattr['__align']))
394
395 def to_string(self):
396 """gdb API function.
397
398 This is called from gdb when we try to print a pthread_condattr_t.
399 """
400
401 return 'pthread_condattr_t'
402
403 def children(self):
404 """gdb API function.
405
406 This is called from gdb when we try to print a pthread_condattr_t.
407 """
408
409 return self.values
410
411 def read_values(self):
412 """Read the condattr's info and store it in self.values.
413
414 The data contained in self.values will be returned by the Iterator
415 created in self.children.
416 """
417
ed19993b 418 clock_id = (self.condattr >> 1) & ((1 << COND_CLOCK_BITS) - 1)
23b5cae1 419
26e21ad3
MG
420 if clock_id != 0:
421 self.values.append(('Clock ID', 'CLOCK_MONOTONIC'))
422 else:
423 self.values.append(('Clock ID', 'CLOCK_REALTIME'))
23b5cae1
MG
424
425 if self.condattr & 1:
426 self.values.append(('Shared', 'Yes'))
427 else:
428 self.values.append(('Shared', 'No'))
429
430class RWLockPrinter(object):
431 """Pretty printer for pthread_rwlock_t."""
432
433 def __init__(self, rwlock):
434 """Initialize the printer's internal data structures.
435
436 Args:
437 rwlock: A gdb.value representing a pthread_rwlock_t.
438 """
439
440 data = rwlock['__data']
cc25c8b4
TR
441 self.readers = data['__readers']
442 self.cur_writer = data['__cur_writer']
23b5cae1 443 self.shared = data['__shared']
cc25c8b4 444 self.flags = data['__flags']
23b5cae1
MG
445 self.values = []
446 self.read_values()
447
448 def to_string(self):
449 """gdb API function.
450
451 This is called from gdb when we try to print a pthread_rwlock_t.
452 """
453
454 return 'pthread_rwlock_t'
455
456 def children(self):
457 """gdb API function.
458
459 This is called from gdb when we try to print a pthread_rwlock_t.
460 """
461
462 return self.values
463
464 def read_values(self):
465 """Read the rwlock's info and store it in self.values.
466
467 The data contained in self.values will be returned by the Iterator
468 created in self.children.
469 """
470
471 self.read_status()
472 self.read_attributes()
473
474 def read_status(self):
475 """Read the status of the rwlock."""
476
cc25c8b4
TR
477 if self.readers & PTHREAD_RWLOCK_WRPHASE:
478 if self.readers & PTHREAD_RWLOCK_WRLOCKED:
479 self.values.append(('Status', 'Acquired (Write)'))
480 self.values.append(('Writer ID', self.cur_writer))
481 else:
482 self.values.append(('Status', 'Not acquired'))
23b5cae1 483 else:
cc25c8b4
TR
484 r = self.readers >> PTHREAD_RWLOCK_READER_SHIFT
485 if r > 0:
486 self.values.append(('Status', 'Acquired (Read)'))
487 self.values.append(('Readers', r))
488 else:
489 self.values.append(('Status', 'Not acquired'))
23b5cae1
MG
490
491 def read_attributes(self):
492 """Read the attributes of the rwlock."""
493
494 if self.shared:
495 self.values.append(('Shared', 'Yes'))
496 else:
497 self.values.append(('Shared', 'No'))
498
cc25c8b4
TR
499 if self.flags == PTHREAD_RWLOCK_PREFER_READER_NP:
500 self.values.append(('Prefers', 'Readers'))
501 elif self.flags == PTHREAD_RWLOCK_PREFER_WRITER_NP:
23b5cae1
MG
502 self.values.append(('Prefers', 'Writers'))
503 else:
cc25c8b4 504 self.values.append(('Prefers', 'Writers no recursive readers'))
23b5cae1
MG
505
506class RWLockAttributesPrinter(object):
507 """Pretty printer for pthread_rwlockattr_t.
508
509 In the NPTL this is a type that's always casted to
510 struct pthread_rwlockattr, which has two fields ('lockkind' and 'pshared')
511 containing the actual attributes.
512 """
513
514 def __init__(self, rwlockattr):
515 """Initialize the printer's internal data structures.
516
517 Args:
518 rwlockattr: A gdb.value representing a pthread_rwlockattr_t.
519 """
520
521 self.values = []
522
523 try:
524 rwlockattr_struct = gdb.lookup_type('struct pthread_rwlockattr')
525 self.rwlockattr = rwlockattr.cast(rwlockattr_struct)
526 self.read_values()
527 except gdb.error:
528 # libpthread doesn't have debug symbols, thus we can't find the
529 # real struct type. Just print the union members.
530 self.values.append(('__size', rwlockattr['__size']))
531 self.values.append(('__align', rwlockattr['__align']))
532
533 def to_string(self):
534 """gdb API function.
535
536 This is called from gdb when we try to print a pthread_rwlockattr_t.
537 """
538
539 return 'pthread_rwlockattr_t'
540
541 def children(self):
542 """gdb API function.
543
544 This is called from gdb when we try to print a pthread_rwlockattr_t.
545 """
546
547 return self.values
548
549 def read_values(self):
550 """Read the rwlockattr's info and store it in self.values.
551
552 The data contained in self.values will be returned by the Iterator
553 created in self.children.
554 """
555
556 rwlock_type = self.rwlockattr['lockkind']
557 shared = self.rwlockattr['pshared']
558
559 if shared == PTHREAD_PROCESS_SHARED:
560 self.values.append(('Shared', 'Yes'))
561 else:
562 # PTHREAD_PROCESS_PRIVATE
563 self.values.append(('Shared', 'No'))
564
cc25c8b4 565 if rwlock_type == PTHREAD_RWLOCK_PREFER_READER_NP:
23b5cae1 566 self.values.append(('Prefers', 'Readers'))
cc25c8b4 567 elif rwlock_type == PTHREAD_RWLOCK_PREFER_WRITER_NP:
23b5cae1 568 self.values.append(('Prefers', 'Writers'))
cc25c8b4
TR
569 else:
570 self.values.append(('Prefers', 'Writers no recursive readers'))
23b5cae1
MG
571
572def register(objfile):
573 """Register the pretty printers within the given objfile."""
574
575 printer = gdb.printing.RegexpCollectionPrettyPrinter('glibc-pthread-locks')
576
577 printer.add_printer('pthread_mutex_t', r'^pthread_mutex_t$',
578 MutexPrinter)
579 printer.add_printer('pthread_mutexattr_t', r'^pthread_mutexattr_t$',
580 MutexAttributesPrinter)
581 printer.add_printer('pthread_cond_t', r'^pthread_cond_t$',
582 ConditionVariablePrinter)
583 printer.add_printer('pthread_condattr_t', r'^pthread_condattr_t$',
584 ConditionVariableAttributesPrinter)
585 printer.add_printer('pthread_rwlock_t', r'^pthread_rwlock_t$',
586 RWLockPrinter)
587 printer.add_printer('pthread_rwlockattr_t', r'^pthread_rwlockattr_t$',
588 RWLockAttributesPrinter)
589
590 if objfile == None:
591 objfile = gdb
592
593 gdb.printing.register_pretty_printer(objfile, printer)
594
595register(gdb.current_objfile())