@@ -362,6 +362,7 @@ def subclass_from_type(cls, t):
362
362
'set' : PySetObjectPtr ,
363
363
'frozenset' : PySetObjectPtr ,
364
364
'builtin_function_or_method' : PyCFunctionObjectPtr ,
365
+ 'method-wrapper' : wrapperobject ,
365
366
}
366
367
if tp_name in name_map :
367
368
return name_map [tp_name ]
@@ -1330,6 +1331,39 @@ def write_repr(self, out, visited):
1330
1331
out .write (quote )
1331
1332
1332
1333
1334
+ class wrapperobject (PyObjectPtr ):
1335
+ _typename = 'wrapperobject'
1336
+
1337
+ def safe_name (self ):
1338
+ try :
1339
+ name = self .field ('descr' )['d_base' ]['name' ].string ()
1340
+ return repr (name )
1341
+ except (NullPyObjectPtr , RuntimeError ):
1342
+ return '<unknown name>'
1343
+
1344
+ def safe_tp_name (self ):
1345
+ try :
1346
+ return self .field ('self' )['ob_type' ]['tp_name' ].string ()
1347
+ except (NullPyObjectPtr , RuntimeError ):
1348
+ return '<unknown tp_name>'
1349
+
1350
+ def safe_self_addresss (self ):
1351
+ try :
1352
+ address = long (self .field ('self' ))
1353
+ return '%#x' % address
1354
+ except (NullPyObjectPtr , RuntimeError ):
1355
+ return '<failed to get self address>'
1356
+
1357
+ def proxyval (self , visited ):
1358
+ name = self .safe_name ()
1359
+ tp_name = self .safe_tp_name ()
1360
+ self_address = self .safe_self_addresss ()
1361
+ return ("<method-wrapper %s of %s object at %s>"
1362
+ % (name , tp_name , self_address ))
1363
+
1364
+ def write_repr (self , out , visited ):
1365
+ proxy = self .proxyval (visited )
1366
+ out .write (proxy )
1333
1367
1334
1368
1335
1369
def int_from_int (gdbval ):
@@ -1364,11 +1398,13 @@ def to_string (self):
1364
1398
1365
1399
def pretty_printer_lookup (gdbval ):
1366
1400
type = gdbval .type .unqualified ()
1367
- if type .code == gdb .TYPE_CODE_PTR :
1368
- type = type .target ().unqualified ()
1369
- t = str (type )
1370
- if t in ("PyObject" , "PyFrameObject" , "PyUnicodeObject" ):
1371
- return PyObjectPtrPrinter (gdbval )
1401
+ if type .code != gdb .TYPE_CODE_PTR :
1402
+ return None
1403
+
1404
+ type = type .target ().unqualified ()
1405
+ t = str (type )
1406
+ if t in ("PyObject" , "PyFrameObject" , "PyUnicodeObject" , "wrapperobject" ):
1407
+ return PyObjectPtrPrinter (gdbval )
1372
1408
1373
1409
"""
1374
1410
During development, I've been manually invoking the code in this way:
@@ -1497,11 +1533,8 @@ def is_other_python_frame(self):
1497
1533
return 'Garbage-collecting'
1498
1534
1499
1535
# Detect invocations of PyCFunction instances:
1500
- older = self .older ()
1501
- if not older :
1502
- return False
1503
-
1504
- caller = older ._gdbframe .name ()
1536
+ frame = self ._gdbframe
1537
+ caller = frame .name ()
1505
1538
if not caller :
1506
1539
return False
1507
1540
@@ -1513,18 +1546,25 @@ def is_other_python_frame(self):
1513
1546
# "self" is the (PyObject*) of the 'self'
1514
1547
try :
1515
1548
# Use the prettyprinter for the func:
1516
- func = older . _gdbframe .read_var ('func' )
1549
+ func = frame .read_var ('func' )
1517
1550
return str (func )
1518
1551
except RuntimeError :
1519
1552
return 'PyCFunction invocation (unable to read "func")'
1520
1553
1521
1554
elif caller == '_PyCFunction_FastCallDict' :
1522
1555
try :
1523
- func = older . _gdbframe .read_var ('func_obj' )
1556
+ func = frame .read_var ('func_obj' )
1524
1557
return str (func )
1525
1558
except RuntimeError :
1526
1559
return 'PyCFunction invocation (unable to read "func_obj")'
1527
1560
1561
+ if caller == 'wrapper_call' :
1562
+ try :
1563
+ func = frame .read_var ('wp' )
1564
+ return str (func )
1565
+ except RuntimeError :
1566
+ return '<wrapper_call invocation>'
1567
+
1528
1568
# This frame isn't worth reporting:
1529
1569
return False
1530
1570
0 commit comments