blob: 3ae70974cc1c7eb3c38c7f1c9f41df28fd51c2fc [file] [log] [blame]
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001#!/usr/bin/python
2'''
3From gdb 7 onwards, gdb's build can be configured --with-python, allowing gdb
4to be extended with Python code e.g. for library-specific data visualizations,
5such as for the C++ STL types. Documentation on this API can be seen at:
6http://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html
7
8
9This python module deals with the case when the process being debugged (the
10"inferior process" in gdb parlance) is itself python, or more specifically,
11linked against libpython. In this situation, almost every item of data is a
12(PyObject*), and having the debugger merely print their addresses is not very
13enlightening.
14
15This module embeds knowledge about the implementation details of libpython so
16that we can emit useful visualizations e.g. a string, a list, a dict, a frame
17giving file/line information and the state of local variables
18
19In particular, given a gdb.Value corresponding to a PyObject* in the inferior
20process, we can generate a "proxy value" within the gdb process. For example,
21given a PyObject* in the inferior process that is in fact a PyListObject*
22holding three PyObject* that turn out to be PyStringObject* instances, we can
23generate a proxy value within the gdb process that is a list of strings:
24 ["foo", "bar", "baz"]
25
26Doing so can be expensive for complicated graphs of objects, and could take
27some time, so we also have a "write_repr" method that writes a representation
28of the data to a file-like object. This allows us to stop the traversal by
29having the file-like object raise an exception if it gets too much data.
30
31With both "proxyval" and "write_repr" we keep track of the set of all addresses
32visited so far in the traversal, to avoid infinite recursion due to cycles in
33the graph of object references.
34
35We try to defer gdb.lookup_type() invocations for python types until as late as
36possible: for a dynamically linked python binary, when the process starts in
37the debugger, the libpython.so hasn't been dynamically loaded yet, so none of
38the type names are known to the debugger
39
40The module also extends gdb with some python-specific commands.
41'''
Antoine Pitrou358da5b2013-11-23 17:40:36 +010042
43# NOTE: some gdbs are linked with Python 3, so this file should be dual-syntax
44# compatible (2.6+ and 3.0+). See #19308.
45
46from __future__ import print_function, with_statement
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000047import gdb
Victor Stinnercc1db4b2015-09-03 10:17:28 +020048import locale
Antoine Pitrou358da5b2013-11-23 17:40:36 +010049import os
Georg Brandleefec7b2010-07-14 08:55:55 +000050import sys
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000051
Antoine Pitrou358da5b2013-11-23 17:40:36 +010052if sys.version_info[0] >= 3:
53 unichr = chr
54 xrange = range
55 long = int
56
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000057# Look up the gdb.Type for some standard types:
Victor Stinnerf6f617c2016-04-20 18:23:13 +020058# Those need to be refreshed as types (pointer sizes) may change when
59# gdb loads different executables
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000060
Victor Stinnerf6f617c2016-04-20 18:23:13 +020061def _type_char_ptr():
62 return gdb.lookup_type('char').pointer() # char*
63
64
65def _type_unsigned_char_ptr():
66 return gdb.lookup_type('unsigned char').pointer() # unsigned char*
67
68
69def _sizeof_void_p():
70 return gdb.lookup_type('void').pointer().sizeof
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000071
72
Antoine Pitrou358da5b2013-11-23 17:40:36 +010073Py_TPFLAGS_HEAPTYPE = (1 << 9)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000074
Antoine Pitrou358da5b2013-11-23 17:40:36 +010075Py_TPFLAGS_INT_SUBCLASS = (1 << 23)
76Py_TPFLAGS_LONG_SUBCLASS = (1 << 24)
77Py_TPFLAGS_LIST_SUBCLASS = (1 << 25)
78Py_TPFLAGS_TUPLE_SUBCLASS = (1 << 26)
79Py_TPFLAGS_STRING_SUBCLASS = (1 << 27)
80Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
81Py_TPFLAGS_DICT_SUBCLASS = (1 << 29)
82Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
83Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000084
85
86MAX_OUTPUT_LEN=1024
87
Victor Stinnercc1db4b2015-09-03 10:17:28 +020088ENCODING = locale.getpreferredencoding()
89
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000090class NullPyObjectPtr(RuntimeError):
91 pass
92
93
94def safety_limit(val):
Serhiy Storchaka9a118f12016-04-17 09:37:36 +030095 # Given an integer value from the process being debugged, limit it to some
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000096 # safety threshold so that arbitrary breakage within said process doesn't
97 # break the gdb process too much (e.g. sizes of iterations, sizes of lists)
98 return min(val, 1000)
99
100
101def safe_range(val):
102 # As per range, but don't trust the value too much: cap it to a safety
103 # threshold in case the data was corrupted
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100104 return xrange(safety_limit(int(val)))
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000105
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200106if sys.version_info[0] >= 3:
107 def write_unicode(file, text):
108 file.write(text)
109else:
110 def write_unicode(file, text):
111 # Write a byte or unicode string to file. Unicode strings are encoded to
112 # ENCODING encoding with 'backslashreplace' error handler to avoid
113 # UnicodeEncodeError.
114 if isinstance(text, unicode):
115 text = text.encode(ENCODING, 'backslashreplace')
116 file.write(text)
117
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000118
119class StringTruncated(RuntimeError):
120 pass
121
122class TruncatedStringIO(object):
123 '''Similar to cStringIO, but can truncate the output by raising a
124 StringTruncated exception'''
125 def __init__(self, maxlen=None):
126 self._val = ''
127 self.maxlen = maxlen
128
129 def write(self, data):
130 if self.maxlen:
131 if len(data) + len(self._val) > self.maxlen:
132 # Truncation:
133 self._val += data[0:self.maxlen - len(self._val)]
134 raise StringTruncated()
135
136 self._val += data
137
138 def getvalue(self):
139 return self._val
140
141class PyObjectPtr(object):
142 """
Serhiy Storchaka9a118f12016-04-17 09:37:36 +0300143 Class wrapping a gdb.Value that's either a (PyObject*) within the
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000144 inferior process, or some subclass pointer e.g. (PyStringObject*)
145
146 There will be a subclass for every refined PyObject type that we care
147 about.
148
149 Note that at every stage the underlying pointer could be NULL, point
150 to corrupt data, etc; this is the debugger, after all.
151 """
152 _typename = 'PyObject'
153
154 def __init__(self, gdbval, cast_to=None):
155 if cast_to:
156 self._gdbval = gdbval.cast(cast_to)
157 else:
158 self._gdbval = gdbval
159
160 def field(self, name):
161 '''
162 Get the gdb.Value for the given field within the PyObject, coping with
163 some python 2 versus python 3 differences.
164
165 Various libpython types are defined using the "PyObject_HEAD" and
166 "PyObject_VAR_HEAD" macros.
167
168 In Python 2, this these are defined so that "ob_type" and (for a var
169 object) "ob_size" are fields of the type in question.
170
171 In Python 3, this is defined as an embedded PyVarObject type thus:
172 PyVarObject ob_base;
173 so that the "ob_size" field is located insize the "ob_base" field, and
174 the "ob_type" is most easily accessed by casting back to a (PyObject*).
175 '''
176 if self.is_null():
177 raise NullPyObjectPtr(self)
178
179 if name == 'ob_type':
180 pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type())
181 return pyo_ptr.dereference()[name]
182
183 if name == 'ob_size':
184 try:
185 # Python 2:
186 return self._gdbval.dereference()[name]
187 except RuntimeError:
188 # Python 3:
189 return self._gdbval.dereference()['ob_base'][name]
190
191 # General case: look it up inside the object:
192 return self._gdbval.dereference()[name]
193
194 def pyop_field(self, name):
195 '''
196 Get a PyObjectPtr for the given PyObject* field within this PyObject,
197 coping with some python 2 versus python 3 differences.
198 '''
199 return PyObjectPtr.from_pyobject_ptr(self.field(name))
200
201 def write_field_repr(self, name, out, visited):
202 '''
203 Extract the PyObject* field named "name", and write its representation
204 to file-like object "out"
205 '''
206 field_obj = self.pyop_field(name)
207 field_obj.write_repr(out, visited)
208
209 def get_truncated_repr(self, maxlen):
210 '''
211 Get a repr-like string for the data, but truncate it at "maxlen" bytes
212 (ending the object graph traversal as soon as you do)
213 '''
214 out = TruncatedStringIO(maxlen)
215 try:
216 self.write_repr(out, set())
217 except StringTruncated:
218 # Truncation occurred:
219 return out.getvalue() + '...(truncated)'
220
221 # No truncation occurred:
222 return out.getvalue()
223
224 def type(self):
225 return PyTypeObjectPtr(self.field('ob_type'))
226
227 def is_null(self):
228 return 0 == long(self._gdbval)
229
230 def is_optimized_out(self):
231 '''
232 Is the value of the underlying PyObject* visible to the debugger?
233
234 This can vary with the precise version of the compiler used to build
235 Python, and the precise version of gdb.
236
237 See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with
238 PyEval_EvalFrameEx's "f"
239 '''
240 return self._gdbval.is_optimized_out
241
242 def safe_tp_name(self):
243 try:
Victor Stinnere36f94f2018-06-15 23:59:56 +0200244 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):
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000251 return 'unknown'
252
253 def proxyval(self, visited):
254 '''
255 Scrape a value from the inferior process, and try to represent it
256 within the gdb process, whilst (hopefully) avoiding crashes when
257 the remote data is corrupt.
258
259 Derived classes will override this.
260
261 For example, a PyIntObject* with ob_ival 42 in the inferior process
262 should result in an int(42) in this process.
263
264 visited: a set of all gdb.Value pyobject pointers already visited
265 whilst generating this value (to guard against infinite recursion when
266 visiting object graphs with loops). Analogous to Py_ReprEnter and
267 Py_ReprLeave
268 '''
269
270 class FakeRepr(object):
271 """
272 Class representing a non-descript PyObject* value in the inferior
273 process for when we don't have a custom scraper, intended to have
274 a sane repr().
275 """
276
277 def __init__(self, tp_name, address):
278 self.tp_name = tp_name
279 self.address = address
280
281 def __repr__(self):
282 # For the NULL pointer, we have no way of knowing a type, so
283 # special-case it as per
284 # http://bugs.python.org/issue8032#msg100882
285 if self.address == 0:
286 return '0x0'
287 return '<%s at remote 0x%x>' % (self.tp_name, self.address)
288
289 return FakeRepr(self.safe_tp_name(),
290 long(self._gdbval))
291
292 def write_repr(self, out, visited):
293 '''
294 Write a string representation of the value scraped from the inferior
295 process to "out", a file-like object.
296 '''
297 # Default implementation: generate a proxy value and write its repr
298 # However, this could involve a lot of work for complicated objects,
299 # so for derived classes we specialize this
300 return out.write(repr(self.proxyval(visited)))
301
302 @classmethod
303 def subclass_from_type(cls, t):
304 '''
305 Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
306 (PyTypeObject*), determine the corresponding subclass of PyObjectPtr
307 to use
308
309 Ideally, we would look up the symbols for the global types, but that
310 isn't working yet:
311 (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
312 Traceback (most recent call last):
313 File "<string>", line 1, in <module>
314 NotImplementedError: Symbol type not yet supported in Python scripts.
315 Error while executing Python code.
316
317 For now, we use tp_flags, after doing some string comparisons on the
318 tp_name for some special-cases that don't seem to be visible through
319 flags
320 '''
321 try:
322 tp_name = t.field('tp_name').string()
323 tp_flags = int(t.field('tp_flags'))
Victor Stinnere36f94f2018-06-15 23:59:56 +0200324 # RuntimeError: NULL pointers
325 # UnicodeDecodeError: string() fails to decode the bytestring
326 except (RuntimeError, UnicodeDecodeError):
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000327 # Handle any kind of error e.g. NULL ptrs by simply using the base
328 # class
329 return cls
330
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100331 #print('tp_flags = 0x%08x' % tp_flags)
332 #print('tp_name = %r' % tp_name)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000333
334 name_map = {'bool': PyBoolObjectPtr,
335 'classobj': PyClassObjectPtr,
336 'instance': PyInstanceObjectPtr,
337 'NoneType': PyNoneStructPtr,
338 'frame': PyFrameObjectPtr,
339 'set' : PySetObjectPtr,
340 'frozenset' : PySetObjectPtr,
341 'builtin_function_or_method' : PyCFunctionObjectPtr,
Victor Stinnere36f94f2018-06-15 23:59:56 +0200342 'method-wrapper': wrapperobject,
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000343 }
344 if tp_name in name_map:
345 return name_map[tp_name]
346
347 if tp_flags & Py_TPFLAGS_HEAPTYPE:
348 return HeapTypeObjectPtr
349
350 if tp_flags & Py_TPFLAGS_INT_SUBCLASS:
351 return PyIntObjectPtr
352 if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
353 return PyLongObjectPtr
354 if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
355 return PyListObjectPtr
356 if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
357 return PyTupleObjectPtr
358 if tp_flags & Py_TPFLAGS_STRING_SUBCLASS:
359 return PyStringObjectPtr
360 if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
361 return PyUnicodeObjectPtr
362 if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
363 return PyDictObjectPtr
364 if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
365 return PyBaseExceptionObjectPtr
366 #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
367 # return PyTypeObjectPtr
368
369 # Use the base class:
370 return cls
371
372 @classmethod
373 def from_pyobject_ptr(cls, gdbval):
374 '''
375 Try to locate the appropriate derived class dynamically, and cast
376 the pointer accordingly.
377 '''
378 try:
379 p = PyObjectPtr(gdbval)
380 cls = cls.subclass_from_type(p.type())
381 return cls(gdbval, cast_to=cls.get_gdb_type())
382 except RuntimeError:
383 # Handle any kind of error e.g. NULL ptrs by simply using the base
384 # class
385 pass
386 return cls(gdbval)
387
388 @classmethod
389 def get_gdb_type(cls):
390 return gdb.lookup_type(cls._typename).pointer()
391
392 def as_address(self):
393 return long(self._gdbval)
394
395
396class ProxyAlreadyVisited(object):
397 '''
398 Placeholder proxy to use when protecting against infinite recursion due to
399 loops in the object graph.
400
401 Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
402 '''
403 def __init__(self, rep):
404 self._rep = rep
405
406 def __repr__(self):
407 return self._rep
408
409
410def _write_instance_repr(out, visited, name, pyop_attrdict, address):
411 '''Shared code for use by old-style and new-style classes:
412 write a representation to file-like object "out"'''
413 out.write('<')
414 out.write(name)
415
416 # Write dictionary of instance attributes:
417 if isinstance(pyop_attrdict, PyDictObjectPtr):
418 out.write('(')
419 first = True
420 for pyop_arg, pyop_val in pyop_attrdict.iteritems():
421 if not first:
422 out.write(', ')
423 first = False
424 out.write(pyop_arg.proxyval(visited))
425 out.write('=')
426 pyop_val.write_repr(out, visited)
427 out.write(')')
428 out.write(' at remote 0x%x>' % address)
429
430
431class InstanceProxy(object):
432
433 def __init__(self, cl_name, attrdict, address):
434 self.cl_name = cl_name
435 self.attrdict = attrdict
436 self.address = address
437
438 def __repr__(self):
439 if isinstance(self.attrdict, dict):
440 kwargs = ', '.join(["%s=%r" % (arg, val)
441 for arg, val in self.attrdict.iteritems()])
442 return '<%s(%s) at remote 0x%x>' % (self.cl_name,
443 kwargs, self.address)
444 else:
445 return '<%s at remote 0x%x>' % (self.cl_name,
446 self.address)
447
448def _PyObject_VAR_SIZE(typeobj, nitems):
Victor Stinner99cff3f2011-12-19 13:59:58 +0100449 if _PyObject_VAR_SIZE._type_size_t is None:
450 _PyObject_VAR_SIZE._type_size_t = gdb.lookup_type('size_t')
451
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000452 return ( ( typeobj.field('tp_basicsize') +
453 nitems * typeobj.field('tp_itemsize') +
Victor Stinnerf6f617c2016-04-20 18:23:13 +0200454 (_sizeof_void_p() - 1)
455 ) & ~(_sizeof_void_p() - 1)
Victor Stinner99cff3f2011-12-19 13:59:58 +0100456 ).cast(_PyObject_VAR_SIZE._type_size_t)
457_PyObject_VAR_SIZE._type_size_t = None
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000458
459class HeapTypeObjectPtr(PyObjectPtr):
460 _typename = 'PyObject'
461
462 def get_attr_dict(self):
463 '''
464 Get the PyDictObject ptr representing the attribute dictionary
465 (or None if there's a problem)
466 '''
467 try:
468 typeobj = self.type()
469 dictoffset = int_from_int(typeobj.field('tp_dictoffset'))
470 if dictoffset != 0:
471 if dictoffset < 0:
472 type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer()
473 tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size'])
474 if tsize < 0:
475 tsize = -tsize
476 size = _PyObject_VAR_SIZE(typeobj, tsize)
477 dictoffset += size
478 assert dictoffset > 0
Victor Stinnerf6f617c2016-04-20 18:23:13 +0200479 assert dictoffset % _sizeof_void_p() == 0
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000480
Victor Stinnerf6f617c2016-04-20 18:23:13 +0200481 dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000482 PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
483 dictptr = dictptr.cast(PyObjectPtrPtr)
484 return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
485 except RuntimeError:
486 # Corrupt data somewhere; fail safe
487 pass
488
489 # Not found, or some kind of error:
490 return None
491
492 def proxyval(self, visited):
493 '''
494 Support for new-style classes.
495
496 Currently we just locate the dictionary using a transliteration to
497 python of _PyObject_GetDictPtr, ignoring descriptors
498 '''
499 # Guard against infinite loops:
500 if self.as_address() in visited:
501 return ProxyAlreadyVisited('<...>')
502 visited.add(self.as_address())
503
504 pyop_attr_dict = self.get_attr_dict()
505 if pyop_attr_dict:
506 attr_dict = pyop_attr_dict.proxyval(visited)
507 else:
508 attr_dict = {}
509 tp_name = self.safe_tp_name()
510
511 # New-style class:
512 return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
513
514 def write_repr(self, out, visited):
515 # Guard against infinite loops:
516 if self.as_address() in visited:
517 out.write('<...>')
518 return
519 visited.add(self.as_address())
520
521 pyop_attrdict = self.get_attr_dict()
522 _write_instance_repr(out, visited,
523 self.safe_tp_name(), pyop_attrdict, self.as_address())
524
525class ProxyException(Exception):
526 def __init__(self, tp_name, args):
527 self.tp_name = tp_name
528 self.args = args
529
530 def __repr__(self):
531 return '%s%r' % (self.tp_name, self.args)
532
533class PyBaseExceptionObjectPtr(PyObjectPtr):
534 """
535 Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
536 within the process being debugged.
537 """
538 _typename = 'PyBaseExceptionObject'
539
540 def proxyval(self, visited):
541 # Guard against infinite loops:
542 if self.as_address() in visited:
543 return ProxyAlreadyVisited('(...)')
544 visited.add(self.as_address())
545 arg_proxy = self.pyop_field('args').proxyval(visited)
546 return ProxyException(self.safe_tp_name(),
547 arg_proxy)
548
549 def write_repr(self, out, visited):
550 # Guard against infinite loops:
551 if self.as_address() in visited:
552 out.write('(...)')
553 return
554 visited.add(self.as_address())
555
556 out.write(self.safe_tp_name())
557 self.write_field_repr('args', out, visited)
558
559class PyBoolObjectPtr(PyObjectPtr):
560 """
561 Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
562 <bool> instances (Py_True/Py_False) within the process being debugged.
563 """
564 _typename = 'PyBoolObject'
565
566 def proxyval(self, visited):
567 if int_from_int(self.field('ob_ival')):
568 return True
569 else:
570 return False
571
572
573class PyClassObjectPtr(PyObjectPtr):
574 """
575 Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
576 instance within the process being debugged.
577 """
578 _typename = 'PyClassObject'
579
580
581class BuiltInFunctionProxy(object):
582 def __init__(self, ml_name):
583 self.ml_name = ml_name
584
585 def __repr__(self):
586 return "<built-in function %s>" % self.ml_name
587
588class BuiltInMethodProxy(object):
589 def __init__(self, ml_name, pyop_m_self):
590 self.ml_name = ml_name
591 self.pyop_m_self = pyop_m_self
592
593 def __repr__(self):
594 return ('<built-in method %s of %s object at remote 0x%x>'
595 % (self.ml_name,
596 self.pyop_m_self.safe_tp_name(),
597 self.pyop_m_self.as_address())
598 )
599
600class PyCFunctionObjectPtr(PyObjectPtr):
601 """
602 Class wrapping a gdb.Value that's a PyCFunctionObject*
603 (see Include/methodobject.h and Objects/methodobject.c)
604 """
605 _typename = 'PyCFunctionObject'
606
607 def proxyval(self, visited):
608 m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
Victor Stinnere36f94f2018-06-15 23:59:56 +0200609 try:
610 ml_name = m_ml['ml_name'].string()
611 except UnicodeDecodeError:
612 ml_name = '<ml_name:UnicodeDecodeError>'
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000613
614 pyop_m_self = self.pyop_field('m_self')
615 if pyop_m_self.is_null():
616 return BuiltInFunctionProxy(ml_name)
617 else:
618 return BuiltInMethodProxy(ml_name, pyop_m_self)
619
620
621class PyCodeObjectPtr(PyObjectPtr):
622 """
623 Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance
624 within the process being debugged.
625 """
626 _typename = 'PyCodeObject'
627
628 def addr2line(self, addrq):
629 '''
630 Get the line number for a given bytecode offset
631
632 Analogous to PyCode_Addr2Line; translated from pseudocode in
633 Objects/lnotab_notes.txt
634 '''
635 co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
636
637 # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
638 # not 0, as lnotab_notes.txt has it:
639 lineno = int_from_int(self.field('co_firstlineno'))
640
641 addr = 0
642 for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
643 addr += ord(addr_incr)
644 if addr > addrq:
645 return lineno
646 lineno += ord(line_incr)
647 return lineno
648
649
650class PyDictObjectPtr(PyObjectPtr):
651 """
652 Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
653 within the process being debugged.
654 """
655 _typename = 'PyDictObject'
656
657 def iteritems(self):
658 '''
659 Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
Ezio Melotti6d0f0f22013-08-26 01:31:30 +0300660 analogous to dict.iteritems()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000661 '''
662 for i in safe_range(self.field('ma_mask') + 1):
663 ep = self.field('ma_table') + i
664 pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
665 if not pyop_value.is_null():
666 pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
667 yield (pyop_key, pyop_value)
668
669 def proxyval(self, visited):
670 # Guard against infinite loops:
671 if self.as_address() in visited:
672 return ProxyAlreadyVisited('{...}')
673 visited.add(self.as_address())
674
675 result = {}
676 for pyop_key, pyop_value in self.iteritems():
677 proxy_key = pyop_key.proxyval(visited)
678 proxy_value = pyop_value.proxyval(visited)
679 result[proxy_key] = proxy_value
680 return result
681
682 def write_repr(self, out, visited):
683 # Guard against infinite loops:
684 if self.as_address() in visited:
685 out.write('{...}')
686 return
687 visited.add(self.as_address())
688
689 out.write('{')
690 first = True
691 for pyop_key, pyop_value in self.iteritems():
692 if not first:
693 out.write(', ')
694 first = False
695 pyop_key.write_repr(out, visited)
696 out.write(': ')
697 pyop_value.write_repr(out, visited)
698 out.write('}')
699
700class PyInstanceObjectPtr(PyObjectPtr):
701 _typename = 'PyInstanceObject'
702
703 def proxyval(self, visited):
704 # Guard against infinite loops:
705 if self.as_address() in visited:
706 return ProxyAlreadyVisited('<...>')
707 visited.add(self.as_address())
708
709 # Get name of class:
710 in_class = self.pyop_field('in_class')
711 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
712
713 # Get dictionary of instance attributes:
714 in_dict = self.pyop_field('in_dict').proxyval(visited)
715
716 # Old-style class:
717 return InstanceProxy(cl_name, in_dict, long(self._gdbval))
718
719 def write_repr(self, out, visited):
720 # Guard against infinite loops:
721 if self.as_address() in visited:
722 out.write('<...>')
723 return
724 visited.add(self.as_address())
725
726 # Old-style class:
727
728 # Get name of class:
729 in_class = self.pyop_field('in_class')
730 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
731
732 # Get dictionary of instance attributes:
733 pyop_in_dict = self.pyop_field('in_dict')
734
735 _write_instance_repr(out, visited,
736 cl_name, pyop_in_dict, self.as_address())
737
738class PyIntObjectPtr(PyObjectPtr):
739 _typename = 'PyIntObject'
740
741 def proxyval(self, visited):
742 result = int_from_int(self.field('ob_ival'))
743 return result
744
745class PyListObjectPtr(PyObjectPtr):
746 _typename = 'PyListObject'
747
748 def __getitem__(self, i):
749 # Get the gdb.Value for the (PyObject*) with the given index:
750 field_ob_item = self.field('ob_item')
751 return field_ob_item[i]
752
753 def proxyval(self, visited):
754 # Guard against infinite loops:
755 if self.as_address() in visited:
756 return ProxyAlreadyVisited('[...]')
757 visited.add(self.as_address())
758
759 result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
760 for i in safe_range(int_from_int(self.field('ob_size')))]
761 return result
762
763 def write_repr(self, out, visited):
764 # Guard against infinite loops:
765 if self.as_address() in visited:
766 out.write('[...]')
767 return
768 visited.add(self.as_address())
769
770 out.write('[')
771 for i in safe_range(int_from_int(self.field('ob_size'))):
772 if i > 0:
773 out.write(', ')
774 element = PyObjectPtr.from_pyobject_ptr(self[i])
775 element.write_repr(out, visited)
776 out.write(']')
777
778class PyLongObjectPtr(PyObjectPtr):
779 _typename = 'PyLongObject'
780
781 def proxyval(self, visited):
782 '''
783 Python's Include/longobjrep.h has this declaration:
784 struct _longobject {
785 PyObject_VAR_HEAD
786 digit ob_digit[1];
787 };
788
789 with this description:
790 The absolute value of a number is equal to
791 SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
792 Negative numbers are represented with ob_size < 0;
793 zero is represented by ob_size == 0.
794
795 where SHIFT can be either:
796 #define PyLong_SHIFT 30
797 #define PyLong_SHIFT 15
798 '''
799 ob_size = long(self.field('ob_size'))
800 if ob_size == 0:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100801 return 0
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000802
803 ob_digit = self.field('ob_digit')
804
805 if gdb.lookup_type('digit').sizeof == 2:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100806 SHIFT = 15
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000807 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100808 SHIFT = 30
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000809
810 digits = [long(ob_digit[i]) * 2**(SHIFT*i)
811 for i in safe_range(abs(ob_size))]
812 result = sum(digits)
813 if ob_size < 0:
814 result = -result
815 return result
816
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100817 def write_repr(self, out, visited):
818 # This ensures the trailing 'L' is printed when gdb is linked
819 # with a Python 3 interpreter.
820 out.write(repr(self.proxyval(visited)).rstrip('L'))
821 out.write('L')
822
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000823
824class PyNoneStructPtr(PyObjectPtr):
825 """
826 Class wrapping a gdb.Value that's a PyObject* pointing to the
827 singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
828 """
829 _typename = 'PyObject'
830
831 def proxyval(self, visited):
832 return None
833
834
835class PyFrameObjectPtr(PyObjectPtr):
836 _typename = 'PyFrameObject'
837
Victor Stinner99cff3f2011-12-19 13:59:58 +0100838 def __init__(self, gdbval, cast_to=None):
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000839 PyObjectPtr.__init__(self, gdbval, cast_to)
840
841 if not self.is_optimized_out():
842 self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
843 self.co_name = self.co.pyop_field('co_name')
844 self.co_filename = self.co.pyop_field('co_filename')
845
846 self.f_lineno = int_from_int(self.field('f_lineno'))
847 self.f_lasti = int_from_int(self.field('f_lasti'))
848 self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
849 self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
850
851 def iter_locals(self):
852 '''
853 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
854 the local variables of this frame
855 '''
856 if self.is_optimized_out():
857 return
858
859 f_localsplus = self.field('f_localsplus')
860 for i in safe_range(self.co_nlocals):
861 pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
862 if not pyop_value.is_null():
863 pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
864 yield (pyop_name, pyop_value)
865
866 def iter_globals(self):
867 '''
868 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
869 the global variables of this frame
870 '''
871 if self.is_optimized_out():
Victor Stinner99cff3f2011-12-19 13:59:58 +0100872 return ()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000873
874 pyop_globals = self.pyop_field('f_globals')
875 return pyop_globals.iteritems()
876
877 def iter_builtins(self):
878 '''
879 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
880 the builtin variables
881 '''
882 if self.is_optimized_out():
Victor Stinner99cff3f2011-12-19 13:59:58 +0100883 return ()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000884
885 pyop_builtins = self.pyop_field('f_builtins')
886 return pyop_builtins.iteritems()
887
888 def get_var_by_name(self, name):
889 '''
890 Look for the named local variable, returning a (PyObjectPtr, scope) pair
891 where scope is a string 'local', 'global', 'builtin'
892
893 If not found, return (None, None)
894 '''
895 for pyop_name, pyop_value in self.iter_locals():
896 if name == pyop_name.proxyval(set()):
897 return pyop_value, 'local'
898 for pyop_name, pyop_value in self.iter_globals():
899 if name == pyop_name.proxyval(set()):
900 return pyop_value, 'global'
901 for pyop_name, pyop_value in self.iter_builtins():
902 if name == pyop_name.proxyval(set()):
903 return pyop_value, 'builtin'
904 return None, None
905
906 def filename(self):
907 '''Get the path of the current Python source file, as a string'''
908 if self.is_optimized_out():
909 return '(frame information optimized out)'
910 return self.co_filename.proxyval(set())
911
912 def current_line_num(self):
913 '''Get current line number as an integer (1-based)
914
915 Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
916
917 See Objects/lnotab_notes.txt
918 '''
919 if self.is_optimized_out():
920 return None
921 f_trace = self.field('f_trace')
922 if long(f_trace) != 0:
923 # we have a non-NULL f_trace:
924 return self.f_lineno
925 else:
926 #try:
927 return self.co.addr2line(self.f_lasti)
928 #except ValueError:
929 # return self.f_lineno
930
931 def current_line(self):
932 '''Get the text of the current source line as a string, with a trailing
933 newline character'''
934 if self.is_optimized_out():
935 return '(frame information optimized out)'
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200936 filename = self.filename()
937 try:
938 f = open(filename, 'r')
939 except IOError:
940 return None
941 with f:
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000942 all_lines = f.readlines()
943 # Convert from 1-based current_line_num to 0-based list offset:
944 return all_lines[self.current_line_num()-1]
945
946 def write_repr(self, out, visited):
947 if self.is_optimized_out():
948 out.write('(frame information optimized out)')
949 return
950 out.write('Frame 0x%x, for file %s, line %i, in %s ('
951 % (self.as_address(),
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200952 self.co_filename.proxyval(visited),
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000953 self.current_line_num(),
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200954 self.co_name.proxyval(visited)))
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000955 first = True
956 for pyop_name, pyop_value in self.iter_locals():
957 if not first:
958 out.write(', ')
959 first = False
960
961 out.write(pyop_name.proxyval(visited))
962 out.write('=')
963 pyop_value.write_repr(out, visited)
964
965 out.write(')')
966
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200967 def print_traceback(self):
968 if self.is_optimized_out():
969 sys.stdout.write(' (frame information optimized out)\n')
970 return
971 visited = set()
972 sys.stdout.write(' File "%s", line %i, in %s\n'
973 % (self.co_filename.proxyval(visited),
974 self.current_line_num(),
975 self.co_name.proxyval(visited)))
976
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000977class PySetObjectPtr(PyObjectPtr):
978 _typename = 'PySetObject'
979
980 def proxyval(self, visited):
981 # Guard against infinite loops:
982 if self.as_address() in visited:
983 return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
984 visited.add(self.as_address())
985
986 members = []
987 table = self.field('table')
988 for i in safe_range(self.field('mask')+1):
989 setentry = table[i]
990 key = setentry['key']
991 if key != 0:
992 key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
993 if key_proxy != '<dummy key>':
994 members.append(key_proxy)
995 if self.safe_tp_name() == 'frozenset':
996 return frozenset(members)
997 else:
998 return set(members)
999
1000 def write_repr(self, out, visited):
1001 out.write(self.safe_tp_name())
1002
1003 # Guard against infinite loops:
1004 if self.as_address() in visited:
1005 out.write('(...)')
1006 return
1007 visited.add(self.as_address())
1008
1009 out.write('([')
1010 first = True
1011 table = self.field('table')
1012 for i in safe_range(self.field('mask')+1):
1013 setentry = table[i]
1014 key = setentry['key']
1015 if key != 0:
1016 pyop_key = PyObjectPtr.from_pyobject_ptr(key)
1017 key_proxy = pyop_key.proxyval(visited) # FIXME!
1018 if key_proxy != '<dummy key>':
1019 if not first:
1020 out.write(', ')
1021 first = False
1022 pyop_key.write_repr(out, visited)
1023 out.write('])')
1024
1025
1026class PyStringObjectPtr(PyObjectPtr):
1027 _typename = 'PyStringObject'
1028
1029 def __str__(self):
1030 field_ob_size = self.field('ob_size')
1031 field_ob_sval = self.field('ob_sval')
Victor Stinnerf6f617c2016-04-20 18:23:13 +02001032 char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr())
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001033 # When gdb is linked with a Python 3 interpreter, this is really
1034 # a latin-1 mojibake decoding of the original string...
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001035 return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
1036
1037 def proxyval(self, visited):
1038 return str(self)
1039
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001040 def write_repr(self, out, visited):
1041 val = repr(self.proxyval(visited))
1042 if sys.version_info[0] >= 3:
1043 val = val.encode('ascii', 'backslashreplace').decode('ascii')
1044 out.write(val)
1045
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001046class PyTupleObjectPtr(PyObjectPtr):
1047 _typename = 'PyTupleObject'
1048
1049 def __getitem__(self, i):
1050 # Get the gdb.Value for the (PyObject*) with the given index:
1051 field_ob_item = self.field('ob_item')
1052 return field_ob_item[i]
1053
1054 def proxyval(self, visited):
1055 # Guard against infinite loops:
1056 if self.as_address() in visited:
1057 return ProxyAlreadyVisited('(...)')
1058 visited.add(self.as_address())
1059
1060 result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
1061 for i in safe_range(int_from_int(self.field('ob_size')))])
1062 return result
1063
1064 def write_repr(self, out, visited):
1065 # Guard against infinite loops:
1066 if self.as_address() in visited:
1067 out.write('(...)')
1068 return
1069 visited.add(self.as_address())
1070
1071 out.write('(')
1072 for i in safe_range(int_from_int(self.field('ob_size'))):
1073 if i > 0:
1074 out.write(', ')
1075 element = PyObjectPtr.from_pyobject_ptr(self[i])
1076 element.write_repr(out, visited)
1077 if self.field('ob_size') == 1:
1078 out.write(',)')
1079 else:
1080 out.write(')')
1081
1082class PyTypeObjectPtr(PyObjectPtr):
1083 _typename = 'PyTypeObject'
1084
1085
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001086if sys.maxunicode >= 0x10000:
1087 _unichr = unichr
1088else:
1089 # Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb
1090 def _unichr(x):
1091 if x < 0x10000:
1092 return unichr(x)
1093 x -= 0x10000
1094 ch1 = 0xD800 | (x >> 10)
1095 ch2 = 0xDC00 | (x & 0x3FF)
1096 return unichr(ch1) + unichr(ch2)
1097
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001098class PyUnicodeObjectPtr(PyObjectPtr):
1099 _typename = 'PyUnicodeObject'
1100
Victor Stinnerb1556c52010-05-20 11:29:45 +00001101 def char_width(self):
1102 _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
1103 return _type_Py_UNICODE.sizeof
1104
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001105 def proxyval(self, visited):
1106 # From unicodeobject.h:
1107 # Py_ssize_t length; /* Length of raw Unicode data in buffer */
1108 # Py_UNICODE *str; /* Raw Unicode buffer */
1109 field_length = long(self.field('length'))
1110 field_str = self.field('str')
1111
1112 # Gather a list of ints from the Py_UNICODE array; these are either
1113 # UCS-2 or UCS-4 code points:
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001114 if self.char_width() > 2:
1115 Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
1116 else:
1117 # A more elaborate routine if sizeof(Py_UNICODE) is 2 in the
1118 # inferior process: we must join surrogate pairs.
1119 Py_UNICODEs = []
1120 i = 0
1121 limit = safety_limit(field_length)
1122 while i < limit:
1123 ucs = int(field_str[i])
1124 i += 1
1125 if ucs < 0xD800 or ucs >= 0xDC00 or i == field_length:
1126 Py_UNICODEs.append(ucs)
1127 continue
1128 # This could be a surrogate pair.
1129 ucs2 = int(field_str[i])
1130 if ucs2 < 0xDC00 or ucs2 > 0xDFFF:
1131 continue
1132 code = (ucs & 0x03FF) << 10
1133 code |= ucs2 & 0x03FF
1134 code += 0x00010000
1135 Py_UNICODEs.append(code)
1136 i += 1
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001137
1138 # Convert the int code points to unicode characters, and generate a
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001139 # local unicode instance.
1140 # This splits surrogate pairs if sizeof(Py_UNICODE) is 2 here (in gdb).
Victor Stinnere36f94f2018-06-15 23:59:56 +02001141 result = u''.join([
1142 (_unichr(ucs) if ucs <= 0x10ffff else '\ufffd')
1143 for ucs in Py_UNICODEs])
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001144 return result
1145
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001146 def write_repr(self, out, visited):
1147 val = repr(self.proxyval(visited))
1148 if sys.version_info[0] >= 3:
1149 val = val.encode('ascii', 'backslashreplace').decode('ascii')
1150 # This ensures the 'u' prefix is printed when gdb is linked
1151 # with a Python 3 interpreter.
1152 out.write('u')
1153 out.write(val.lstrip('u'))
1154
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001155
Victor Stinnere36f94f2018-06-15 23:59:56 +02001156class 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
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001191def int_from_int(gdbval):
1192 return int(str(gdbval))
1193
1194
1195def stringify(val):
1196 # TODO: repr() puts everything on one line; pformat can be nicer, but
1197 # can lead to v.long results; this function isolates the choice
1198 if True:
1199 return repr(val)
1200 else:
1201 from pprint import pformat
1202 return pformat(val)
1203
1204
1205class PyObjectPtrPrinter:
1206 "Prints a (PyObject*)"
1207
1208 def __init__ (self, gdbval):
1209 self.gdbval = gdbval
1210
1211 def to_string (self):
1212 pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
1213 if True:
1214 return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1215 else:
1216 # Generate full proxy value then stringify it.
1217 # Doing so could be expensive
1218 proxyval = pyop.proxyval(set())
1219 return stringify(proxyval)
1220
1221def pretty_printer_lookup(gdbval):
1222 type = gdbval.type.unqualified()
Victor Stinnere36f94f2018-06-15 23:59:56 +02001223 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)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001230
1231"""
1232During development, I've been manually invoking the code in this way:
1233(gdb) python
1234
1235import sys
1236sys.path.append('/home/david/coding/python-gdb')
1237import libpython
1238end
1239
1240then reloading it after each edit like this:
1241(gdb) python reload(libpython)
1242
1243The following code should ensure that the prettyprinter is registered
1244if the code is autoloaded by gdb when visiting libpython.so, provided
1245that this python file is installed to the same path as the library (or its
1246.debug file) plus a "-gdb.py" suffix, e.g:
1247 /usr/lib/libpython2.6.so.1.0-gdb.py
1248 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
1249"""
1250def register (obj):
Victor Stinnere36f94f2018-06-15 23:59:56 +02001251 if obj is None:
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001252 obj = gdb
1253
1254 # Wire up the pretty-printer
1255 obj.pretty_printers.append(pretty_printer_lookup)
1256
1257register (gdb.current_objfile ())
1258
1259
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001260
1261# Unfortunately, the exact API exposed by the gdb module varies somewhat
1262# from build to build
1263# See http://bugs.python.org/issue8279?#msg102276
1264
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001265class Frame(object):
1266 '''
1267 Wrapper for gdb.Frame, adding various methods
1268 '''
1269 def __init__(self, gdbframe):
1270 self._gdbframe = gdbframe
1271
1272 def older(self):
1273 older = self._gdbframe.older()
1274 if older:
1275 return Frame(older)
1276 else:
1277 return None
1278
1279 def newer(self):
1280 newer = self._gdbframe.newer()
1281 if newer:
1282 return Frame(newer)
1283 else:
1284 return None
1285
1286 def select(self):
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001287 '''If supported, select this frame and return True; return False if unsupported
1288
1289 Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
1290 onwards, but absent on Ubuntu buildbot'''
1291 if not hasattr(self._gdbframe, 'select'):
1292 print ('Unable to select frame: '
1293 'this build of gdb does not expose a gdb.Frame.select method')
1294 return False
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001295 self._gdbframe.select()
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001296 return True
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001297
1298 def get_index(self):
1299 '''Calculate index of frame, starting at 0 for the newest frame within
1300 this thread'''
1301 index = 0
1302 # Go down until you reach the newest frame:
1303 iter_frame = self
1304 while iter_frame.newer():
1305 index += 1
1306 iter_frame = iter_frame.newer()
1307 return index
1308
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001309 # We divide frames into:
1310 # - "python frames":
1311 # - "bytecode frames" i.e. PyEval_EvalFrameEx
1312 # - "other python frames": things that are of interest from a python
1313 # POV, but aren't bytecode (e.g. GC, GIL)
1314 # - everything else
1315
1316 def is_python_frame(self):
1317 '''Is this a PyEval_EvalFrameEx frame, or some other important
1318 frame? (see is_other_python_frame for what "important" means in this
1319 context)'''
1320 if self.is_evalframeex():
1321 return True
1322 if self.is_other_python_frame():
1323 return True
1324 return False
1325
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001326 def is_evalframeex(self):
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001327 '''Is this a PyEval_EvalFrameEx frame?'''
Victor Stinnera92e81b2010-04-20 22:28:31 +00001328 if self._gdbframe.name() == 'PyEval_EvalFrameEx':
1329 '''
1330 I believe we also need to filter on the inline
1331 struct frame_id.inline_depth, only regarding frames with
1332 an inline depth of 0 as actually being this function
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001333
Victor Stinnera92e81b2010-04-20 22:28:31 +00001334 So we reject those with type gdb.INLINE_FRAME
1335 '''
1336 if self._gdbframe.type() == gdb.NORMAL_FRAME:
1337 # We have a PyEval_EvalFrameEx frame:
1338 return True
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001339
1340 return False
1341
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001342 def is_other_python_frame(self):
1343 '''Is this frame worth displaying in python backtraces?
1344 Examples:
1345 - waiting on the GIL
1346 - garbage-collecting
1347 - within a CFunction
1348 If it is, return a descriptive string
1349 For other frames, return False
1350 '''
1351 if self.is_waiting_for_gil():
1352 return 'Waiting for the GIL'
Victor Stinnere36f94f2018-06-15 23:59:56 +02001353
1354 if self.is_gc_collect():
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001355 return 'Garbage-collecting'
Victor Stinnere36f94f2018-06-15 23:59:56 +02001356
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
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001390
1391 # This frame isn't worth reporting:
1392 return False
1393
1394 def is_waiting_for_gil(self):
1395 '''Is this frame waiting on the GIL?'''
1396 # This assumes the _POSIX_THREADS version of Python/ceval_gil.h:
1397 name = self._gdbframe.name()
1398 if name:
1399 return ('PyThread_acquire_lock' in name
1400 and 'lock_PyThread_acquire_lock' not in name)
1401
1402 def is_gc_collect(self):
1403 '''Is this frame "collect" within the garbage-collector?'''
1404 return self._gdbframe.name() == 'collect'
1405
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001406 def get_pyop(self):
1407 try:
1408 f = self._gdbframe.read_var('f')
Victor Stinner99cff3f2011-12-19 13:59:58 +01001409 frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1410 if not frame.is_optimized_out():
1411 return frame
1412 # gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
1413 # because it was "optimized out". Try to get "f" from the frame
1414 # of the caller, PyEval_EvalCodeEx().
1415 orig_frame = frame
1416 caller = self._gdbframe.older()
1417 if caller:
1418 f = caller.read_var('f')
1419 frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1420 if not frame.is_optimized_out():
1421 return frame
1422 return orig_frame
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001423 except ValueError:
1424 return None
1425
1426 @classmethod
1427 def get_selected_frame(cls):
1428 _gdbframe = gdb.selected_frame()
1429 if _gdbframe:
1430 return Frame(_gdbframe)
1431 return None
1432
1433 @classmethod
1434 def get_selected_python_frame(cls):
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001435 '''Try to obtain the Frame for the python-related code in the selected
1436 frame, or None'''
Victor Stinnere36f94f2018-06-15 23:59:56 +02001437 try:
1438 frame = cls.get_selected_frame()
1439 except gdb.error:
1440 # No frame: Python didn't start yet
1441 return None
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001442
1443 while frame:
1444 if frame.is_python_frame():
1445 return frame
1446 frame = frame.older()
1447
1448 # Not found:
1449 return None
1450
1451 @classmethod
1452 def get_selected_bytecode_frame(cls):
1453 '''Try to obtain the Frame for the python bytecode interpreter in the
1454 selected GDB frame, or None'''
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001455 frame = cls.get_selected_frame()
1456
1457 while frame:
1458 if frame.is_evalframeex():
1459 return frame
1460 frame = frame.older()
1461
1462 # Not found:
1463 return None
1464
1465 def print_summary(self):
1466 if self.is_evalframeex():
1467 pyop = self.get_pyop()
1468 if pyop:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001469 line = pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1470 write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line))
Victor Stinner99cff3f2011-12-19 13:59:58 +01001471 if not pyop.is_optimized_out():
1472 line = pyop.current_line()
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001473 if line is not None:
1474 sys.stdout.write(' %s\n' % line.strip())
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001475 else:
1476 sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1477 else:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001478 info = self.is_other_python_frame()
1479 if info:
1480 sys.stdout.write('#%i %s\n' % (self.get_index(), info))
1481 else:
1482 sys.stdout.write('#%i\n' % self.get_index())
1483
1484 def print_traceback(self):
1485 if self.is_evalframeex():
1486 pyop = self.get_pyop()
1487 if pyop:
1488 pyop.print_traceback()
1489 if not pyop.is_optimized_out():
1490 line = pyop.current_line()
1491 if line is not None:
1492 sys.stdout.write(' %s\n' % line.strip())
1493 else:
1494 sys.stdout.write(' (unable to read python frame information)\n')
1495 else:
1496 info = self.is_other_python_frame()
1497 if info:
1498 sys.stdout.write(' %s\n' % info)
1499 else:
1500 sys.stdout.write(' (not a python frame)\n')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001501
1502class PyList(gdb.Command):
1503 '''List the current Python source code, if any
1504
1505 Use
1506 py-list START
1507 to list at a different line number within the python source.
1508
1509 Use
1510 py-list START, END
1511 to list a specific range of lines within the python source.
1512 '''
1513
1514 def __init__(self):
1515 gdb.Command.__init__ (self,
1516 "py-list",
1517 gdb.COMMAND_FILES,
1518 gdb.COMPLETE_NONE)
1519
1520
1521 def invoke(self, args, from_tty):
1522 import re
1523
1524 start = None
1525 end = None
1526
1527 m = re.match(r'\s*(\d+)\s*', args)
1528 if m:
1529 start = int(m.group(0))
1530 end = start + 10
1531
1532 m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
1533 if m:
1534 start, end = map(int, m.groups())
1535
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001536 # py-list requires an actual PyEval_EvalFrameEx frame:
1537 frame = Frame.get_selected_bytecode_frame()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001538 if not frame:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001539 print('Unable to locate gdb frame for python bytecode interpreter')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001540 return
1541
1542 pyop = frame.get_pyop()
Victor Stinner99cff3f2011-12-19 13:59:58 +01001543 if not pyop or pyop.is_optimized_out():
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001544 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001545 return
1546
1547 filename = pyop.filename()
1548 lineno = pyop.current_line_num()
1549
1550 if start is None:
1551 start = lineno - 5
1552 end = lineno + 5
1553
1554 if start<1:
1555 start = 1
1556
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001557 try:
1558 f = open(filename, 'r')
1559 except IOError as err:
1560 sys.stdout.write('Unable to open %s: %s\n'
1561 % (filename, err))
1562 return
1563 with f:
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001564 all_lines = f.readlines()
1565 # start and end are 1-based, all_lines is 0-based;
1566 # so [start-1:end] as a python slice gives us [start, end] as a
1567 # closed interval
1568 for i, line in enumerate(all_lines[start-1:end]):
1569 linestr = str(i+start)
1570 # Highlight current line:
1571 if i + start == lineno:
1572 linestr = '>' + linestr
1573 sys.stdout.write('%4s %s' % (linestr, line))
1574
1575
1576# ...and register the command:
1577PyList()
1578
1579def move_in_stack(move_up):
1580 '''Move up or down the stack (for the py-up/py-down command)'''
1581 frame = Frame.get_selected_python_frame()
Victor Stinnere36f94f2018-06-15 23:59:56 +02001582 if not frame:
1583 print('Unable to locate python frame')
1584 return
1585
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001586 while frame:
1587 if move_up:
1588 iter_frame = frame.older()
1589 else:
1590 iter_frame = frame.newer()
1591
1592 if not iter_frame:
1593 break
1594
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001595 if iter_frame.is_python_frame():
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001596 # Result:
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001597 if iter_frame.select():
1598 iter_frame.print_summary()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001599 return
1600
1601 frame = iter_frame
1602
1603 if move_up:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001604 print('Unable to find an older python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001605 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001606 print('Unable to find a newer python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001607
1608class PyUp(gdb.Command):
1609 'Select and print the python stack frame that called this one (if any)'
1610 def __init__(self):
1611 gdb.Command.__init__ (self,
1612 "py-up",
1613 gdb.COMMAND_STACK,
1614 gdb.COMPLETE_NONE)
1615
1616
1617 def invoke(self, args, from_tty):
1618 move_in_stack(move_up=True)
1619
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001620class PyDown(gdb.Command):
1621 'Select and print the python stack frame called by this one (if any)'
1622 def __init__(self):
1623 gdb.Command.__init__ (self,
1624 "py-down",
1625 gdb.COMMAND_STACK,
1626 gdb.COMPLETE_NONE)
1627
1628
1629 def invoke(self, args, from_tty):
1630 move_in_stack(move_up=False)
1631
Victor Stinnera92e81b2010-04-20 22:28:31 +00001632# Not all builds of gdb have gdb.Frame.select
1633if hasattr(gdb.Frame, 'select'):
1634 PyUp()
1635 PyDown()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001636
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001637class PyBacktraceFull(gdb.Command):
1638 'Display the current python frame and all the frames within its call stack (if any)'
1639 def __init__(self):
1640 gdb.Command.__init__ (self,
1641 "py-bt-full",
1642 gdb.COMMAND_STACK,
1643 gdb.COMPLETE_NONE)
1644
1645
1646 def invoke(self, args, from_tty):
1647 frame = Frame.get_selected_python_frame()
Victor Stinnere36f94f2018-06-15 23:59:56 +02001648 if not frame:
1649 print('Unable to locate python frame')
1650 return
1651
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001652 while frame:
1653 if frame.is_python_frame():
1654 frame.print_summary()
1655 frame = frame.older()
1656
1657PyBacktraceFull()
1658
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001659class PyBacktrace(gdb.Command):
1660 'Display the current python frame and all the frames within its call stack (if any)'
1661 def __init__(self):
1662 gdb.Command.__init__ (self,
1663 "py-bt",
1664 gdb.COMMAND_STACK,
1665 gdb.COMPLETE_NONE)
1666
1667
1668 def invoke(self, args, from_tty):
1669 frame = Frame.get_selected_python_frame()
Victor Stinnere36f94f2018-06-15 23:59:56 +02001670 if not frame:
1671 print('Unable to locate python frame')
1672 return
1673
1674 sys.stdout.write('Traceback (most recent call first):\n')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001675 while frame:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001676 if frame.is_python_frame():
1677 frame.print_traceback()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001678 frame = frame.older()
1679
1680PyBacktrace()
1681
1682class PyPrint(gdb.Command):
1683 'Look up the given python variable name, and print it'
1684 def __init__(self):
1685 gdb.Command.__init__ (self,
1686 "py-print",
1687 gdb.COMMAND_DATA,
1688 gdb.COMPLETE_NONE)
1689
1690
1691 def invoke(self, args, from_tty):
1692 name = str(args)
1693
1694 frame = Frame.get_selected_python_frame()
1695 if not frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001696 print('Unable to locate python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001697 return
1698
1699 pyop_frame = frame.get_pyop()
1700 if not pyop_frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001701 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001702 return
1703
1704 pyop_var, scope = pyop_frame.get_var_by_name(name)
1705
1706 if pyop_var:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001707 print('%s %r = %s'
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001708 % (scope,
1709 name,
1710 pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
1711 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001712 print('%r not found' % name)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001713
1714PyPrint()
1715
1716class PyLocals(gdb.Command):
1717 'Look up the given python variable name, and print it'
1718 def __init__(self):
1719 gdb.Command.__init__ (self,
1720 "py-locals",
1721 gdb.COMMAND_DATA,
1722 gdb.COMPLETE_NONE)
1723
1724
1725 def invoke(self, args, from_tty):
1726 name = str(args)
1727
1728 frame = Frame.get_selected_python_frame()
1729 if not frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001730 print('Unable to locate python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001731 return
1732
1733 pyop_frame = frame.get_pyop()
1734 if not pyop_frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001735 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001736 return
1737
1738 for pyop_name, pyop_value in pyop_frame.iter_locals():
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001739 print('%s = %s'
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001740 % (pyop_name.proxyval(set()),
1741 pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
1742
1743PyLocals()