]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | """ | |
33 | ||
34 | from __future__ import print_function | |
35 | ||
36 | import gdb | |
37 | import gdb.printing | |
38 | from nptl_lock_constants import * | |
39 | ||
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') | |
45 | } | |
46 | ||
47 | class 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 | |
227 | class 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 |
304 | class 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 |
369 | class 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 | ||
430 | class 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 | |
506 | class 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 | |
572 | def 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 | ||
595 | register(gdb.current_objfile()) |