@@ -241,12 +241,13 @@ def is_optimized_out(self):
241241
242242 def safe_tp_name (self ):
243243 try :
244- return self .type ().field ('tp_name' ).string ()
245- except NullPyObjectPtr :
246- # NULL tp_name?
247- return 'unknown'
248- except RuntimeError :
249- # Can't even read the object at all?
244+ ob_type = self .type ()
245+ tp_name = ob_type .field ('tp_name' )
246+ return tp_name .string ()
247+ # NullPyObjectPtr: NULL tp_name?
248+ # RuntimeError: Can't even read the object at all?
249+ # UnicodeDecodeError: Failed to decode tp_name bytestring
250+ except (NullPyObjectPtr , RuntimeError , UnicodeDecodeError ):
250251 return 'unknown'
251252
252253 def proxyval (self , visited ):
@@ -320,7 +321,9 @@ def subclass_from_type(cls, t):
320321 try :
321322 tp_name = t .field ('tp_name' ).string ()
322323 tp_flags = int (t .field ('tp_flags' ))
323- except RuntimeError :
324+ # RuntimeError: NULL pointers
325+ # UnicodeDecodeError: string() fails to decode the bytestring
326+ except (RuntimeError , UnicodeDecodeError ):
324327 # Handle any kind of error e.g. NULL ptrs by simply using the base
325328 # class
326329 return cls
@@ -336,6 +339,7 @@ def subclass_from_type(cls, t):
336339 'set' : PySetObjectPtr ,
337340 'frozenset' : PySetObjectPtr ,
338341 'builtin_function_or_method' : PyCFunctionObjectPtr ,
342+ 'method-wrapper' : wrapperobject ,
339343 }
340344 if tp_name in name_map :
341345 return name_map [tp_name ]
@@ -602,7 +606,10 @@ class PyCFunctionObjectPtr(PyObjectPtr):
602606
603607 def proxyval (self , visited ):
604608 m_ml = self .field ('m_ml' ) # m_ml is a (PyMethodDef*)
605- ml_name = m_ml ['ml_name' ].string ()
609+ try :
610+ ml_name = m_ml ['ml_name' ].string ()
611+ except UnicodeDecodeError :
612+ ml_name = '<ml_name:UnicodeDecodeError>'
606613
607614 pyop_m_self = self .pyop_field ('m_self' )
608615 if pyop_m_self .is_null ():
@@ -1131,7 +1138,9 @@ def proxyval(self, visited):
11311138 # Convert the int code points to unicode characters, and generate a
11321139 # local unicode instance.
11331140 # This splits surrogate pairs if sizeof(Py_UNICODE) is 2 here (in gdb).
1134- result = u'' .join ([_unichr (ucs ) for ucs in Py_UNICODEs ])
1141+ result = u'' .join ([
1142+ (_unichr (ucs ) if ucs <= 0x10ffff else '\ufffd ' )
1143+ for ucs in Py_UNICODEs ])
11351144 return result
11361145
11371146 def write_repr (self , out , visited ):
@@ -1144,6 +1153,41 @@ def write_repr(self, out, visited):
11441153 out .write (val .lstrip ('u' ))
11451154
11461155
1156+ class wrapperobject (PyObjectPtr ):
1157+ _typename = 'wrapperobject'
1158+
1159+ def safe_name (self ):
1160+ try :
1161+ name = self .field ('descr' )['d_base' ]['name' ].string ()
1162+ return repr (name )
1163+ except (NullPyObjectPtr , RuntimeError , UnicodeDecodeError ):
1164+ return '<unknown name>'
1165+
1166+ def safe_tp_name (self ):
1167+ try :
1168+ return self .field ('self' )['ob_type' ]['tp_name' ].string ()
1169+ except (NullPyObjectPtr , RuntimeError , UnicodeDecodeError ):
1170+ return '<unknown tp_name>'
1171+
1172+ def safe_self_addresss (self ):
1173+ try :
1174+ address = long (self .field ('self' ))
1175+ return '%#x' % address
1176+ except (NullPyObjectPtr , RuntimeError ):
1177+ return '<failed to get self address>'
1178+
1179+ def proxyval (self , visited ):
1180+ name = self .safe_name ()
1181+ tp_name = self .safe_tp_name ()
1182+ self_address = self .safe_self_addresss ()
1183+ return ("<method-wrapper %s of %s object at %s>"
1184+ % (name , tp_name , self_address ))
1185+
1186+ def write_repr (self , out , visited ):
1187+ proxy = self .proxyval (visited )
1188+ out .write (proxy )
1189+
1190+
11471191def int_from_int (gdbval ):
11481192 return int (str (gdbval ))
11491193
@@ -1176,11 +1220,13 @@ def to_string (self):
11761220
11771221def pretty_printer_lookup (gdbval ):
11781222 type = gdbval .type .unqualified ()
1179- if type .code == gdb .TYPE_CODE_PTR :
1180- type = type .target ().unqualified ()
1181- t = str (type )
1182- if t in ("PyObject" , "PyFrameObject" ):
1183- return PyObjectPtrPrinter (gdbval )
1223+ if type .code != gdb .TYPE_CODE_PTR :
1224+ return None
1225+
1226+ type = type .target ().unqualified ()
1227+ t = str (type )
1228+ if t in ("PyObject" , "PyFrameObject" , "PyUnicodeObject" , "wrapperobject" ):
1229+ return PyObjectPtrPrinter (gdbval )
11841230
11851231"""
11861232During development, I've been manually invoking the code in this way:
@@ -1202,7 +1248,7 @@ def pretty_printer_lookup(gdbval):
12021248 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
12031249"""
12041250def register (obj ):
1205- if obj == None :
1251+ if obj is None :
12061252 obj = gdb
12071253
12081254 # Wire up the pretty-printer
@@ -1304,23 +1350,43 @@ def is_other_python_frame(self):
13041350 '''
13051351 if self .is_waiting_for_gil ():
13061352 return 'Waiting for the GIL'
1307- elif self .is_gc_collect ():
1353+
1354+ if self .is_gc_collect ():
13081355 return 'Garbage-collecting'
1309- else :
1310- # Detect invocations of PyCFunction instances:
1311- older = self .older ()
1312- if older and older ._gdbframe .name () == 'PyCFunction_Call' :
1313- # Within that frame:
1314- # "func" is the local containing the PyObject* of the
1315- # PyCFunctionObject instance
1316- # "f" is the same value, but cast to (PyCFunctionObject*)
1317- # "self" is the (PyObject*) of the 'self'
1318- try :
1319- # Use the prettyprinter for the func:
1320- func = older ._gdbframe .read_var ('func' )
1321- return str (func )
1322- except RuntimeError :
1323- return 'PyCFunction invocation (unable to read "func")'
1356+
1357+ # Detect invocations of PyCFunction instances:
1358+ frame = self ._gdbframe
1359+ caller = frame .name ()
1360+ if not caller :
1361+ return False
1362+
1363+ if caller == 'PyCFunction_Call' :
1364+ arg_name = 'func'
1365+ # Within that frame:
1366+ # "func" is the local containing the PyObject* of the
1367+ # PyCFunctionObject instance
1368+ # "f" is the same value, but cast to (PyCFunctionObject*)
1369+ # "self" is the (PyObject*) of the 'self'
1370+ try :
1371+ # Use the prettyprinter for the func:
1372+ func = frame .read_var (arg_name )
1373+ return str (func )
1374+ except ValueError :
1375+ return ('PyCFunction invocation (unable to read %s: '
1376+ 'missing debuginfos?)' % arg_name )
1377+ except RuntimeError :
1378+ return 'PyCFunction invocation (unable to read %s)' % arg_name
1379+
1380+ if caller == 'wrapper_call' :
1381+ arg_name = 'wp'
1382+ try :
1383+ func = frame .read_var (arg_name )
1384+ return str (func )
1385+ except ValueError :
1386+ return ('<wrapper_call invocation (unable to read %s: '
1387+ 'missing debuginfos?)>' % arg_name )
1388+ except RuntimeError :
1389+ return '<wrapper_call invocation (unable to read %s)>' % arg_name
13241390
13251391 # This frame isn't worth reporting:
13261392 return False
@@ -1368,7 +1434,11 @@ def get_selected_frame(cls):
13681434 def get_selected_python_frame (cls ):
13691435 '''Try to obtain the Frame for the python-related code in the selected
13701436 frame, or None'''
1371- frame = cls .get_selected_frame ()
1437+ try :
1438+ frame = cls .get_selected_frame ()
1439+ except gdb .error :
1440+ # No frame: Python didn't start yet
1441+ return None
13721442
13731443 while frame :
13741444 if frame .is_python_frame ():
@@ -1509,6 +1579,10 @@ def invoke(self, args, from_tty):
15091579def move_in_stack (move_up ):
15101580 '''Move up or down the stack (for the py-up/py-down command)'''
15111581 frame = Frame .get_selected_python_frame ()
1582+ if not frame :
1583+ print ('Unable to locate python frame' )
1584+ return
1585+
15121586 while frame :
15131587 if move_up :
15141588 iter_frame = frame .older ()
@@ -1571,6 +1645,10 @@ def __init__(self):
15711645
15721646 def invoke (self , args , from_tty ):
15731647 frame = Frame .get_selected_python_frame ()
1648+ if not frame :
1649+ print ('Unable to locate python frame' )
1650+ return
1651+
15741652 while frame :
15751653 if frame .is_python_frame ():
15761654 frame .print_summary ()
@@ -1588,8 +1666,12 @@ def __init__(self):
15881666
15891667
15901668 def invoke (self , args , from_tty ):
1591- sys .stdout .write ('Traceback (most recent call first):\n ' )
15921669 frame = Frame .get_selected_python_frame ()
1670+ if not frame :
1671+ print ('Unable to locate python frame' )
1672+ return
1673+
1674+ sys .stdout .write ('Traceback (most recent call first):\n ' )
15931675 while frame :
15941676 if frame .is_python_frame ():
15951677 frame .print_traceback ()
0 commit comments