blob: e713654d84c1d35e6ce3c92836c10b9a917da948 [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:
58_type_char_ptr = gdb.lookup_type('char').pointer() # char*
59_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
60_type_void_ptr = gdb.lookup_type('void').pointer() # void*
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000061
62SIZEOF_VOID_P = _type_void_ptr.sizeof
63
64
Antoine Pitrou358da5b2013-11-23 17:40:36 +010065Py_TPFLAGS_HEAPTYPE = (1 << 9)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000066
Antoine Pitrou358da5b2013-11-23 17:40:36 +010067Py_TPFLAGS_INT_SUBCLASS = (1 << 23)
68Py_TPFLAGS_LONG_SUBCLASS = (1 << 24)
69Py_TPFLAGS_LIST_SUBCLASS = (1 << 25)
70Py_TPFLAGS_TUPLE_SUBCLASS = (1 << 26)
71Py_TPFLAGS_STRING_SUBCLASS = (1 << 27)
72Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
73Py_TPFLAGS_DICT_SUBCLASS = (1 << 29)
74Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
75Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000076
77
78MAX_OUTPUT_LEN=1024
79
Victor Stinnercc1db4b2015-09-03 10:17:28 +020080ENCODING = locale.getpreferredencoding()
81
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000082class NullPyObjectPtr(RuntimeError):
83 pass
84
85
86def safety_limit(val):
Serhiy Storchaka9a118f12016-04-17 09:37:36 +030087 # Given an integer value from the process being debugged, limit it to some
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000088 # safety threshold so that arbitrary breakage within said process doesn't
89 # break the gdb process too much (e.g. sizes of iterations, sizes of lists)
90 return min(val, 1000)
91
92
93def safe_range(val):
94 # As per range, but don't trust the value too much: cap it to a safety
95 # threshold in case the data was corrupted
Antoine Pitrou358da5b2013-11-23 17:40:36 +010096 return xrange(safety_limit(int(val)))
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +000097
Victor Stinnercc1db4b2015-09-03 10:17:28 +020098if sys.version_info[0] >= 3:
99 def write_unicode(file, text):
100 file.write(text)
101else:
102 def write_unicode(file, text):
103 # Write a byte or unicode string to file. Unicode strings are encoded to
104 # ENCODING encoding with 'backslashreplace' error handler to avoid
105 # UnicodeEncodeError.
106 if isinstance(text, unicode):
107 text = text.encode(ENCODING, 'backslashreplace')
108 file.write(text)
109
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000110
111class StringTruncated(RuntimeError):
112 pass
113
114class TruncatedStringIO(object):
115 '''Similar to cStringIO, but can truncate the output by raising a
116 StringTruncated exception'''
117 def __init__(self, maxlen=None):
118 self._val = ''
119 self.maxlen = maxlen
120
121 def write(self, data):
122 if self.maxlen:
123 if len(data) + len(self._val) > self.maxlen:
124 # Truncation:
125 self._val += data[0:self.maxlen - len(self._val)]
126 raise StringTruncated()
127
128 self._val += data
129
130 def getvalue(self):
131 return self._val
132
133class PyObjectPtr(object):
134 """
Serhiy Storchaka9a118f12016-04-17 09:37:36 +0300135 Class wrapping a gdb.Value that's either a (PyObject*) within the
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000136 inferior process, or some subclass pointer e.g. (PyStringObject*)
137
138 There will be a subclass for every refined PyObject type that we care
139 about.
140
141 Note that at every stage the underlying pointer could be NULL, point
142 to corrupt data, etc; this is the debugger, after all.
143 """
144 _typename = 'PyObject'
145
146 def __init__(self, gdbval, cast_to=None):
147 if cast_to:
148 self._gdbval = gdbval.cast(cast_to)
149 else:
150 self._gdbval = gdbval
151
152 def field(self, name):
153 '''
154 Get the gdb.Value for the given field within the PyObject, coping with
155 some python 2 versus python 3 differences.
156
157 Various libpython types are defined using the "PyObject_HEAD" and
158 "PyObject_VAR_HEAD" macros.
159
160 In Python 2, this these are defined so that "ob_type" and (for a var
161 object) "ob_size" are fields of the type in question.
162
163 In Python 3, this is defined as an embedded PyVarObject type thus:
164 PyVarObject ob_base;
165 so that the "ob_size" field is located insize the "ob_base" field, and
166 the "ob_type" is most easily accessed by casting back to a (PyObject*).
167 '''
168 if self.is_null():
169 raise NullPyObjectPtr(self)
170
171 if name == 'ob_type':
172 pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type())
173 return pyo_ptr.dereference()[name]
174
175 if name == 'ob_size':
176 try:
177 # Python 2:
178 return self._gdbval.dereference()[name]
179 except RuntimeError:
180 # Python 3:
181 return self._gdbval.dereference()['ob_base'][name]
182
183 # General case: look it up inside the object:
184 return self._gdbval.dereference()[name]
185
186 def pyop_field(self, name):
187 '''
188 Get a PyObjectPtr for the given PyObject* field within this PyObject,
189 coping with some python 2 versus python 3 differences.
190 '''
191 return PyObjectPtr.from_pyobject_ptr(self.field(name))
192
193 def write_field_repr(self, name, out, visited):
194 '''
195 Extract the PyObject* field named "name", and write its representation
196 to file-like object "out"
197 '''
198 field_obj = self.pyop_field(name)
199 field_obj.write_repr(out, visited)
200
201 def get_truncated_repr(self, maxlen):
202 '''
203 Get a repr-like string for the data, but truncate it at "maxlen" bytes
204 (ending the object graph traversal as soon as you do)
205 '''
206 out = TruncatedStringIO(maxlen)
207 try:
208 self.write_repr(out, set())
209 except StringTruncated:
210 # Truncation occurred:
211 return out.getvalue() + '...(truncated)'
212
213 # No truncation occurred:
214 return out.getvalue()
215
216 def type(self):
217 return PyTypeObjectPtr(self.field('ob_type'))
218
219 def is_null(self):
220 return 0 == long(self._gdbval)
221
222 def is_optimized_out(self):
223 '''
224 Is the value of the underlying PyObject* visible to the debugger?
225
226 This can vary with the precise version of the compiler used to build
227 Python, and the precise version of gdb.
228
229 See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with
230 PyEval_EvalFrameEx's "f"
231 '''
232 return self._gdbval.is_optimized_out
233
234 def safe_tp_name(self):
235 try:
236 return self.type().field('tp_name').string()
237 except NullPyObjectPtr:
238 # NULL tp_name?
239 return 'unknown'
240 except RuntimeError:
241 # Can't even read the object at all?
242 return 'unknown'
243
244 def proxyval(self, visited):
245 '''
246 Scrape a value from the inferior process, and try to represent it
247 within the gdb process, whilst (hopefully) avoiding crashes when
248 the remote data is corrupt.
249
250 Derived classes will override this.
251
252 For example, a PyIntObject* with ob_ival 42 in the inferior process
253 should result in an int(42) in this process.
254
255 visited: a set of all gdb.Value pyobject pointers already visited
256 whilst generating this value (to guard against infinite recursion when
257 visiting object graphs with loops). Analogous to Py_ReprEnter and
258 Py_ReprLeave
259 '''
260
261 class FakeRepr(object):
262 """
263 Class representing a non-descript PyObject* value in the inferior
264 process for when we don't have a custom scraper, intended to have
265 a sane repr().
266 """
267
268 def __init__(self, tp_name, address):
269 self.tp_name = tp_name
270 self.address = address
271
272 def __repr__(self):
273 # For the NULL pointer, we have no way of knowing a type, so
274 # special-case it as per
275 # http://bugs.python.org/issue8032#msg100882
276 if self.address == 0:
277 return '0x0'
278 return '<%s at remote 0x%x>' % (self.tp_name, self.address)
279
280 return FakeRepr(self.safe_tp_name(),
281 long(self._gdbval))
282
283 def write_repr(self, out, visited):
284 '''
285 Write a string representation of the value scraped from the inferior
286 process to "out", a file-like object.
287 '''
288 # Default implementation: generate a proxy value and write its repr
289 # However, this could involve a lot of work for complicated objects,
290 # so for derived classes we specialize this
291 return out.write(repr(self.proxyval(visited)))
292
293 @classmethod
294 def subclass_from_type(cls, t):
295 '''
296 Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
297 (PyTypeObject*), determine the corresponding subclass of PyObjectPtr
298 to use
299
300 Ideally, we would look up the symbols for the global types, but that
301 isn't working yet:
302 (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
303 Traceback (most recent call last):
304 File "<string>", line 1, in <module>
305 NotImplementedError: Symbol type not yet supported in Python scripts.
306 Error while executing Python code.
307
308 For now, we use tp_flags, after doing some string comparisons on the
309 tp_name for some special-cases that don't seem to be visible through
310 flags
311 '''
312 try:
313 tp_name = t.field('tp_name').string()
314 tp_flags = int(t.field('tp_flags'))
315 except RuntimeError:
316 # Handle any kind of error e.g. NULL ptrs by simply using the base
317 # class
318 return cls
319
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100320 #print('tp_flags = 0x%08x' % tp_flags)
321 #print('tp_name = %r' % tp_name)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000322
323 name_map = {'bool': PyBoolObjectPtr,
324 'classobj': PyClassObjectPtr,
325 'instance': PyInstanceObjectPtr,
326 'NoneType': PyNoneStructPtr,
327 'frame': PyFrameObjectPtr,
328 'set' : PySetObjectPtr,
329 'frozenset' : PySetObjectPtr,
330 'builtin_function_or_method' : PyCFunctionObjectPtr,
331 }
332 if tp_name in name_map:
333 return name_map[tp_name]
334
335 if tp_flags & Py_TPFLAGS_HEAPTYPE:
336 return HeapTypeObjectPtr
337
338 if tp_flags & Py_TPFLAGS_INT_SUBCLASS:
339 return PyIntObjectPtr
340 if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
341 return PyLongObjectPtr
342 if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
343 return PyListObjectPtr
344 if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
345 return PyTupleObjectPtr
346 if tp_flags & Py_TPFLAGS_STRING_SUBCLASS:
347 return PyStringObjectPtr
348 if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
349 return PyUnicodeObjectPtr
350 if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
351 return PyDictObjectPtr
352 if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
353 return PyBaseExceptionObjectPtr
354 #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
355 # return PyTypeObjectPtr
356
357 # Use the base class:
358 return cls
359
360 @classmethod
361 def from_pyobject_ptr(cls, gdbval):
362 '''
363 Try to locate the appropriate derived class dynamically, and cast
364 the pointer accordingly.
365 '''
366 try:
367 p = PyObjectPtr(gdbval)
368 cls = cls.subclass_from_type(p.type())
369 return cls(gdbval, cast_to=cls.get_gdb_type())
370 except RuntimeError:
371 # Handle any kind of error e.g. NULL ptrs by simply using the base
372 # class
373 pass
374 return cls(gdbval)
375
376 @classmethod
377 def get_gdb_type(cls):
378 return gdb.lookup_type(cls._typename).pointer()
379
380 def as_address(self):
381 return long(self._gdbval)
382
383
384class ProxyAlreadyVisited(object):
385 '''
386 Placeholder proxy to use when protecting against infinite recursion due to
387 loops in the object graph.
388
389 Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
390 '''
391 def __init__(self, rep):
392 self._rep = rep
393
394 def __repr__(self):
395 return self._rep
396
397
398def _write_instance_repr(out, visited, name, pyop_attrdict, address):
399 '''Shared code for use by old-style and new-style classes:
400 write a representation to file-like object "out"'''
401 out.write('<')
402 out.write(name)
403
404 # Write dictionary of instance attributes:
405 if isinstance(pyop_attrdict, PyDictObjectPtr):
406 out.write('(')
407 first = True
408 for pyop_arg, pyop_val in pyop_attrdict.iteritems():
409 if not first:
410 out.write(', ')
411 first = False
412 out.write(pyop_arg.proxyval(visited))
413 out.write('=')
414 pyop_val.write_repr(out, visited)
415 out.write(')')
416 out.write(' at remote 0x%x>' % address)
417
418
419class InstanceProxy(object):
420
421 def __init__(self, cl_name, attrdict, address):
422 self.cl_name = cl_name
423 self.attrdict = attrdict
424 self.address = address
425
426 def __repr__(self):
427 if isinstance(self.attrdict, dict):
428 kwargs = ', '.join(["%s=%r" % (arg, val)
429 for arg, val in self.attrdict.iteritems()])
430 return '<%s(%s) at remote 0x%x>' % (self.cl_name,
431 kwargs, self.address)
432 else:
433 return '<%s at remote 0x%x>' % (self.cl_name,
434 self.address)
435
436def _PyObject_VAR_SIZE(typeobj, nitems):
Victor Stinner99cff3f2011-12-19 13:59:58 +0100437 if _PyObject_VAR_SIZE._type_size_t is None:
438 _PyObject_VAR_SIZE._type_size_t = gdb.lookup_type('size_t')
439
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000440 return ( ( typeobj.field('tp_basicsize') +
441 nitems * typeobj.field('tp_itemsize') +
442 (SIZEOF_VOID_P - 1)
443 ) & ~(SIZEOF_VOID_P - 1)
Victor Stinner99cff3f2011-12-19 13:59:58 +0100444 ).cast(_PyObject_VAR_SIZE._type_size_t)
445_PyObject_VAR_SIZE._type_size_t = None
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000446
447class HeapTypeObjectPtr(PyObjectPtr):
448 _typename = 'PyObject'
449
450 def get_attr_dict(self):
451 '''
452 Get the PyDictObject ptr representing the attribute dictionary
453 (or None if there's a problem)
454 '''
455 try:
456 typeobj = self.type()
457 dictoffset = int_from_int(typeobj.field('tp_dictoffset'))
458 if dictoffset != 0:
459 if dictoffset < 0:
460 type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer()
461 tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size'])
462 if tsize < 0:
463 tsize = -tsize
464 size = _PyObject_VAR_SIZE(typeobj, tsize)
465 dictoffset += size
466 assert dictoffset > 0
467 assert dictoffset % SIZEOF_VOID_P == 0
468
469 dictptr = self._gdbval.cast(_type_char_ptr) + dictoffset
470 PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
471 dictptr = dictptr.cast(PyObjectPtrPtr)
472 return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
473 except RuntimeError:
474 # Corrupt data somewhere; fail safe
475 pass
476
477 # Not found, or some kind of error:
478 return None
479
480 def proxyval(self, visited):
481 '''
482 Support for new-style classes.
483
484 Currently we just locate the dictionary using a transliteration to
485 python of _PyObject_GetDictPtr, ignoring descriptors
486 '''
487 # Guard against infinite loops:
488 if self.as_address() in visited:
489 return ProxyAlreadyVisited('<...>')
490 visited.add(self.as_address())
491
492 pyop_attr_dict = self.get_attr_dict()
493 if pyop_attr_dict:
494 attr_dict = pyop_attr_dict.proxyval(visited)
495 else:
496 attr_dict = {}
497 tp_name = self.safe_tp_name()
498
499 # New-style class:
500 return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
501
502 def write_repr(self, out, visited):
503 # Guard against infinite loops:
504 if self.as_address() in visited:
505 out.write('<...>')
506 return
507 visited.add(self.as_address())
508
509 pyop_attrdict = self.get_attr_dict()
510 _write_instance_repr(out, visited,
511 self.safe_tp_name(), pyop_attrdict, self.as_address())
512
513class ProxyException(Exception):
514 def __init__(self, tp_name, args):
515 self.tp_name = tp_name
516 self.args = args
517
518 def __repr__(self):
519 return '%s%r' % (self.tp_name, self.args)
520
521class PyBaseExceptionObjectPtr(PyObjectPtr):
522 """
523 Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
524 within the process being debugged.
525 """
526 _typename = 'PyBaseExceptionObject'
527
528 def proxyval(self, visited):
529 # Guard against infinite loops:
530 if self.as_address() in visited:
531 return ProxyAlreadyVisited('(...)')
532 visited.add(self.as_address())
533 arg_proxy = self.pyop_field('args').proxyval(visited)
534 return ProxyException(self.safe_tp_name(),
535 arg_proxy)
536
537 def write_repr(self, out, visited):
538 # Guard against infinite loops:
539 if self.as_address() in visited:
540 out.write('(...)')
541 return
542 visited.add(self.as_address())
543
544 out.write(self.safe_tp_name())
545 self.write_field_repr('args', out, visited)
546
547class PyBoolObjectPtr(PyObjectPtr):
548 """
549 Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
550 <bool> instances (Py_True/Py_False) within the process being debugged.
551 """
552 _typename = 'PyBoolObject'
553
554 def proxyval(self, visited):
555 if int_from_int(self.field('ob_ival')):
556 return True
557 else:
558 return False
559
560
561class PyClassObjectPtr(PyObjectPtr):
562 """
563 Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
564 instance within the process being debugged.
565 """
566 _typename = 'PyClassObject'
567
568
569class BuiltInFunctionProxy(object):
570 def __init__(self, ml_name):
571 self.ml_name = ml_name
572
573 def __repr__(self):
574 return "<built-in function %s>" % self.ml_name
575
576class BuiltInMethodProxy(object):
577 def __init__(self, ml_name, pyop_m_self):
578 self.ml_name = ml_name
579 self.pyop_m_self = pyop_m_self
580
581 def __repr__(self):
582 return ('<built-in method %s of %s object at remote 0x%x>'
583 % (self.ml_name,
584 self.pyop_m_self.safe_tp_name(),
585 self.pyop_m_self.as_address())
586 )
587
588class PyCFunctionObjectPtr(PyObjectPtr):
589 """
590 Class wrapping a gdb.Value that's a PyCFunctionObject*
591 (see Include/methodobject.h and Objects/methodobject.c)
592 """
593 _typename = 'PyCFunctionObject'
594
595 def proxyval(self, visited):
596 m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
597 ml_name = m_ml['ml_name'].string()
598
599 pyop_m_self = self.pyop_field('m_self')
600 if pyop_m_self.is_null():
601 return BuiltInFunctionProxy(ml_name)
602 else:
603 return BuiltInMethodProxy(ml_name, pyop_m_self)
604
605
606class PyCodeObjectPtr(PyObjectPtr):
607 """
608 Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance
609 within the process being debugged.
610 """
611 _typename = 'PyCodeObject'
612
613 def addr2line(self, addrq):
614 '''
615 Get the line number for a given bytecode offset
616
617 Analogous to PyCode_Addr2Line; translated from pseudocode in
618 Objects/lnotab_notes.txt
619 '''
620 co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
621
622 # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
623 # not 0, as lnotab_notes.txt has it:
624 lineno = int_from_int(self.field('co_firstlineno'))
625
626 addr = 0
627 for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
628 addr += ord(addr_incr)
629 if addr > addrq:
630 return lineno
631 lineno += ord(line_incr)
632 return lineno
633
634
635class PyDictObjectPtr(PyObjectPtr):
636 """
637 Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
638 within the process being debugged.
639 """
640 _typename = 'PyDictObject'
641
642 def iteritems(self):
643 '''
644 Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
Ezio Melotti6d0f0f22013-08-26 01:31:30 +0300645 analogous to dict.iteritems()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000646 '''
647 for i in safe_range(self.field('ma_mask') + 1):
648 ep = self.field('ma_table') + i
649 pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
650 if not pyop_value.is_null():
651 pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
652 yield (pyop_key, pyop_value)
653
654 def proxyval(self, visited):
655 # Guard against infinite loops:
656 if self.as_address() in visited:
657 return ProxyAlreadyVisited('{...}')
658 visited.add(self.as_address())
659
660 result = {}
661 for pyop_key, pyop_value in self.iteritems():
662 proxy_key = pyop_key.proxyval(visited)
663 proxy_value = pyop_value.proxyval(visited)
664 result[proxy_key] = proxy_value
665 return result
666
667 def write_repr(self, out, visited):
668 # Guard against infinite loops:
669 if self.as_address() in visited:
670 out.write('{...}')
671 return
672 visited.add(self.as_address())
673
674 out.write('{')
675 first = True
676 for pyop_key, pyop_value in self.iteritems():
677 if not first:
678 out.write(', ')
679 first = False
680 pyop_key.write_repr(out, visited)
681 out.write(': ')
682 pyop_value.write_repr(out, visited)
683 out.write('}')
684
685class PyInstanceObjectPtr(PyObjectPtr):
686 _typename = 'PyInstanceObject'
687
688 def proxyval(self, visited):
689 # Guard against infinite loops:
690 if self.as_address() in visited:
691 return ProxyAlreadyVisited('<...>')
692 visited.add(self.as_address())
693
694 # Get name of class:
695 in_class = self.pyop_field('in_class')
696 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
697
698 # Get dictionary of instance attributes:
699 in_dict = self.pyop_field('in_dict').proxyval(visited)
700
701 # Old-style class:
702 return InstanceProxy(cl_name, in_dict, long(self._gdbval))
703
704 def write_repr(self, out, visited):
705 # Guard against infinite loops:
706 if self.as_address() in visited:
707 out.write('<...>')
708 return
709 visited.add(self.as_address())
710
711 # Old-style class:
712
713 # Get name of class:
714 in_class = self.pyop_field('in_class')
715 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
716
717 # Get dictionary of instance attributes:
718 pyop_in_dict = self.pyop_field('in_dict')
719
720 _write_instance_repr(out, visited,
721 cl_name, pyop_in_dict, self.as_address())
722
723class PyIntObjectPtr(PyObjectPtr):
724 _typename = 'PyIntObject'
725
726 def proxyval(self, visited):
727 result = int_from_int(self.field('ob_ival'))
728 return result
729
730class PyListObjectPtr(PyObjectPtr):
731 _typename = 'PyListObject'
732
733 def __getitem__(self, i):
734 # Get the gdb.Value for the (PyObject*) with the given index:
735 field_ob_item = self.field('ob_item')
736 return field_ob_item[i]
737
738 def proxyval(self, visited):
739 # Guard against infinite loops:
740 if self.as_address() in visited:
741 return ProxyAlreadyVisited('[...]')
742 visited.add(self.as_address())
743
744 result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
745 for i in safe_range(int_from_int(self.field('ob_size')))]
746 return result
747
748 def write_repr(self, out, visited):
749 # Guard against infinite loops:
750 if self.as_address() in visited:
751 out.write('[...]')
752 return
753 visited.add(self.as_address())
754
755 out.write('[')
756 for i in safe_range(int_from_int(self.field('ob_size'))):
757 if i > 0:
758 out.write(', ')
759 element = PyObjectPtr.from_pyobject_ptr(self[i])
760 element.write_repr(out, visited)
761 out.write(']')
762
763class PyLongObjectPtr(PyObjectPtr):
764 _typename = 'PyLongObject'
765
766 def proxyval(self, visited):
767 '''
768 Python's Include/longobjrep.h has this declaration:
769 struct _longobject {
770 PyObject_VAR_HEAD
771 digit ob_digit[1];
772 };
773
774 with this description:
775 The absolute value of a number is equal to
776 SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
777 Negative numbers are represented with ob_size < 0;
778 zero is represented by ob_size == 0.
779
780 where SHIFT can be either:
781 #define PyLong_SHIFT 30
782 #define PyLong_SHIFT 15
783 '''
784 ob_size = long(self.field('ob_size'))
785 if ob_size == 0:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100786 return 0
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000787
788 ob_digit = self.field('ob_digit')
789
790 if gdb.lookup_type('digit').sizeof == 2:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100791 SHIFT = 15
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000792 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100793 SHIFT = 30
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000794
795 digits = [long(ob_digit[i]) * 2**(SHIFT*i)
796 for i in safe_range(abs(ob_size))]
797 result = sum(digits)
798 if ob_size < 0:
799 result = -result
800 return result
801
Antoine Pitrou358da5b2013-11-23 17:40:36 +0100802 def write_repr(self, out, visited):
803 # This ensures the trailing 'L' is printed when gdb is linked
804 # with a Python 3 interpreter.
805 out.write(repr(self.proxyval(visited)).rstrip('L'))
806 out.write('L')
807
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000808
809class PyNoneStructPtr(PyObjectPtr):
810 """
811 Class wrapping a gdb.Value that's a PyObject* pointing to the
812 singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
813 """
814 _typename = 'PyObject'
815
816 def proxyval(self, visited):
817 return None
818
819
820class PyFrameObjectPtr(PyObjectPtr):
821 _typename = 'PyFrameObject'
822
Victor Stinner99cff3f2011-12-19 13:59:58 +0100823 def __init__(self, gdbval, cast_to=None):
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000824 PyObjectPtr.__init__(self, gdbval, cast_to)
825
826 if not self.is_optimized_out():
827 self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
828 self.co_name = self.co.pyop_field('co_name')
829 self.co_filename = self.co.pyop_field('co_filename')
830
831 self.f_lineno = int_from_int(self.field('f_lineno'))
832 self.f_lasti = int_from_int(self.field('f_lasti'))
833 self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
834 self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
835
836 def iter_locals(self):
837 '''
838 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
839 the local variables of this frame
840 '''
841 if self.is_optimized_out():
842 return
843
844 f_localsplus = self.field('f_localsplus')
845 for i in safe_range(self.co_nlocals):
846 pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
847 if not pyop_value.is_null():
848 pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
849 yield (pyop_name, pyop_value)
850
851 def iter_globals(self):
852 '''
853 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
854 the global variables of this frame
855 '''
856 if self.is_optimized_out():
Victor Stinner99cff3f2011-12-19 13:59:58 +0100857 return ()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000858
859 pyop_globals = self.pyop_field('f_globals')
860 return pyop_globals.iteritems()
861
862 def iter_builtins(self):
863 '''
864 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
865 the builtin variables
866 '''
867 if self.is_optimized_out():
Victor Stinner99cff3f2011-12-19 13:59:58 +0100868 return ()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000869
870 pyop_builtins = self.pyop_field('f_builtins')
871 return pyop_builtins.iteritems()
872
873 def get_var_by_name(self, name):
874 '''
875 Look for the named local variable, returning a (PyObjectPtr, scope) pair
876 where scope is a string 'local', 'global', 'builtin'
877
878 If not found, return (None, None)
879 '''
880 for pyop_name, pyop_value in self.iter_locals():
881 if name == pyop_name.proxyval(set()):
882 return pyop_value, 'local'
883 for pyop_name, pyop_value in self.iter_globals():
884 if name == pyop_name.proxyval(set()):
885 return pyop_value, 'global'
886 for pyop_name, pyop_value in self.iter_builtins():
887 if name == pyop_name.proxyval(set()):
888 return pyop_value, 'builtin'
889 return None, None
890
891 def filename(self):
892 '''Get the path of the current Python source file, as a string'''
893 if self.is_optimized_out():
894 return '(frame information optimized out)'
895 return self.co_filename.proxyval(set())
896
897 def current_line_num(self):
898 '''Get current line number as an integer (1-based)
899
900 Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
901
902 See Objects/lnotab_notes.txt
903 '''
904 if self.is_optimized_out():
905 return None
906 f_trace = self.field('f_trace')
907 if long(f_trace) != 0:
908 # we have a non-NULL f_trace:
909 return self.f_lineno
910 else:
911 #try:
912 return self.co.addr2line(self.f_lasti)
913 #except ValueError:
914 # return self.f_lineno
915
916 def current_line(self):
917 '''Get the text of the current source line as a string, with a trailing
918 newline character'''
919 if self.is_optimized_out():
920 return '(frame information optimized out)'
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200921 filename = self.filename()
922 try:
923 f = open(filename, 'r')
924 except IOError:
925 return None
926 with f:
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000927 all_lines = f.readlines()
928 # Convert from 1-based current_line_num to 0-based list offset:
929 return all_lines[self.current_line_num()-1]
930
931 def write_repr(self, out, visited):
932 if self.is_optimized_out():
933 out.write('(frame information optimized out)')
934 return
935 out.write('Frame 0x%x, for file %s, line %i, in %s ('
936 % (self.as_address(),
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200937 self.co_filename.proxyval(visited),
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000938 self.current_line_num(),
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200939 self.co_name.proxyval(visited)))
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000940 first = True
941 for pyop_name, pyop_value in self.iter_locals():
942 if not first:
943 out.write(', ')
944 first = False
945
946 out.write(pyop_name.proxyval(visited))
947 out.write('=')
948 pyop_value.write_repr(out, visited)
949
950 out.write(')')
951
Victor Stinnercc1db4b2015-09-03 10:17:28 +0200952 def print_traceback(self):
953 if self.is_optimized_out():
954 sys.stdout.write(' (frame information optimized out)\n')
955 return
956 visited = set()
957 sys.stdout.write(' File "%s", line %i, in %s\n'
958 % (self.co_filename.proxyval(visited),
959 self.current_line_num(),
960 self.co_name.proxyval(visited)))
961
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +0000962class PySetObjectPtr(PyObjectPtr):
963 _typename = 'PySetObject'
964
965 def proxyval(self, visited):
966 # Guard against infinite loops:
967 if self.as_address() in visited:
968 return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
969 visited.add(self.as_address())
970
971 members = []
972 table = self.field('table')
973 for i in safe_range(self.field('mask')+1):
974 setentry = table[i]
975 key = setentry['key']
976 if key != 0:
977 key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
978 if key_proxy != '<dummy key>':
979 members.append(key_proxy)
980 if self.safe_tp_name() == 'frozenset':
981 return frozenset(members)
982 else:
983 return set(members)
984
985 def write_repr(self, out, visited):
986 out.write(self.safe_tp_name())
987
988 # Guard against infinite loops:
989 if self.as_address() in visited:
990 out.write('(...)')
991 return
992 visited.add(self.as_address())
993
994 out.write('([')
995 first = True
996 table = self.field('table')
997 for i in safe_range(self.field('mask')+1):
998 setentry = table[i]
999 key = setentry['key']
1000 if key != 0:
1001 pyop_key = PyObjectPtr.from_pyobject_ptr(key)
1002 key_proxy = pyop_key.proxyval(visited) # FIXME!
1003 if key_proxy != '<dummy key>':
1004 if not first:
1005 out.write(', ')
1006 first = False
1007 pyop_key.write_repr(out, visited)
1008 out.write('])')
1009
1010
1011class PyStringObjectPtr(PyObjectPtr):
1012 _typename = 'PyStringObject'
1013
1014 def __str__(self):
1015 field_ob_size = self.field('ob_size')
1016 field_ob_sval = self.field('ob_sval')
1017 char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr)
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001018 # When gdb is linked with a Python 3 interpreter, this is really
1019 # a latin-1 mojibake decoding of the original string...
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001020 return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
1021
1022 def proxyval(self, visited):
1023 return str(self)
1024
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001025 def write_repr(self, out, visited):
1026 val = repr(self.proxyval(visited))
1027 if sys.version_info[0] >= 3:
1028 val = val.encode('ascii', 'backslashreplace').decode('ascii')
1029 out.write(val)
1030
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001031class PyTupleObjectPtr(PyObjectPtr):
1032 _typename = 'PyTupleObject'
1033
1034 def __getitem__(self, i):
1035 # Get the gdb.Value for the (PyObject*) with the given index:
1036 field_ob_item = self.field('ob_item')
1037 return field_ob_item[i]
1038
1039 def proxyval(self, visited):
1040 # Guard against infinite loops:
1041 if self.as_address() in visited:
1042 return ProxyAlreadyVisited('(...)')
1043 visited.add(self.as_address())
1044
1045 result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
1046 for i in safe_range(int_from_int(self.field('ob_size')))])
1047 return result
1048
1049 def write_repr(self, out, visited):
1050 # Guard against infinite loops:
1051 if self.as_address() in visited:
1052 out.write('(...)')
1053 return
1054 visited.add(self.as_address())
1055
1056 out.write('(')
1057 for i in safe_range(int_from_int(self.field('ob_size'))):
1058 if i > 0:
1059 out.write(', ')
1060 element = PyObjectPtr.from_pyobject_ptr(self[i])
1061 element.write_repr(out, visited)
1062 if self.field('ob_size') == 1:
1063 out.write(',)')
1064 else:
1065 out.write(')')
1066
1067class PyTypeObjectPtr(PyObjectPtr):
1068 _typename = 'PyTypeObject'
1069
1070
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001071if sys.maxunicode >= 0x10000:
1072 _unichr = unichr
1073else:
1074 # Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb
1075 def _unichr(x):
1076 if x < 0x10000:
1077 return unichr(x)
1078 x -= 0x10000
1079 ch1 = 0xD800 | (x >> 10)
1080 ch2 = 0xDC00 | (x & 0x3FF)
1081 return unichr(ch1) + unichr(ch2)
1082
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001083class PyUnicodeObjectPtr(PyObjectPtr):
1084 _typename = 'PyUnicodeObject'
1085
Victor Stinnerb1556c52010-05-20 11:29:45 +00001086 def char_width(self):
1087 _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
1088 return _type_Py_UNICODE.sizeof
1089
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001090 def proxyval(self, visited):
1091 # From unicodeobject.h:
1092 # Py_ssize_t length; /* Length of raw Unicode data in buffer */
1093 # Py_UNICODE *str; /* Raw Unicode buffer */
1094 field_length = long(self.field('length'))
1095 field_str = self.field('str')
1096
1097 # Gather a list of ints from the Py_UNICODE array; these are either
1098 # UCS-2 or UCS-4 code points:
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001099 if self.char_width() > 2:
1100 Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
1101 else:
1102 # A more elaborate routine if sizeof(Py_UNICODE) is 2 in the
1103 # inferior process: we must join surrogate pairs.
1104 Py_UNICODEs = []
1105 i = 0
1106 limit = safety_limit(field_length)
1107 while i < limit:
1108 ucs = int(field_str[i])
1109 i += 1
1110 if ucs < 0xD800 or ucs >= 0xDC00 or i == field_length:
1111 Py_UNICODEs.append(ucs)
1112 continue
1113 # This could be a surrogate pair.
1114 ucs2 = int(field_str[i])
1115 if ucs2 < 0xDC00 or ucs2 > 0xDFFF:
1116 continue
1117 code = (ucs & 0x03FF) << 10
1118 code |= ucs2 & 0x03FF
1119 code += 0x00010000
1120 Py_UNICODEs.append(code)
1121 i += 1
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001122
1123 # Convert the int code points to unicode characters, and generate a
Antoine Pitrou2fba0b32010-09-08 21:12:36 +00001124 # local unicode instance.
1125 # This splits surrogate pairs if sizeof(Py_UNICODE) is 2 here (in gdb).
1126 result = u''.join([_unichr(ucs) for ucs in Py_UNICODEs])
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001127 return result
1128
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001129 def write_repr(self, out, visited):
1130 val = repr(self.proxyval(visited))
1131 if sys.version_info[0] >= 3:
1132 val = val.encode('ascii', 'backslashreplace').decode('ascii')
1133 # This ensures the 'u' prefix is printed when gdb is linked
1134 # with a Python 3 interpreter.
1135 out.write('u')
1136 out.write(val.lstrip('u'))
1137
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001138
1139def int_from_int(gdbval):
1140 return int(str(gdbval))
1141
1142
1143def stringify(val):
1144 # TODO: repr() puts everything on one line; pformat can be nicer, but
1145 # can lead to v.long results; this function isolates the choice
1146 if True:
1147 return repr(val)
1148 else:
1149 from pprint import pformat
1150 return pformat(val)
1151
1152
1153class PyObjectPtrPrinter:
1154 "Prints a (PyObject*)"
1155
1156 def __init__ (self, gdbval):
1157 self.gdbval = gdbval
1158
1159 def to_string (self):
1160 pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
1161 if True:
1162 return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1163 else:
1164 # Generate full proxy value then stringify it.
1165 # Doing so could be expensive
1166 proxyval = pyop.proxyval(set())
1167 return stringify(proxyval)
1168
1169def pretty_printer_lookup(gdbval):
1170 type = gdbval.type.unqualified()
1171 if type.code == gdb.TYPE_CODE_PTR:
1172 type = type.target().unqualified()
1173 t = str(type)
1174 if t in ("PyObject", "PyFrameObject"):
1175 return PyObjectPtrPrinter(gdbval)
1176
1177"""
1178During development, I've been manually invoking the code in this way:
1179(gdb) python
1180
1181import sys
1182sys.path.append('/home/david/coding/python-gdb')
1183import libpython
1184end
1185
1186then reloading it after each edit like this:
1187(gdb) python reload(libpython)
1188
1189The following code should ensure that the prettyprinter is registered
1190if the code is autoloaded by gdb when visiting libpython.so, provided
1191that this python file is installed to the same path as the library (or its
1192.debug file) plus a "-gdb.py" suffix, e.g:
1193 /usr/lib/libpython2.6.so.1.0-gdb.py
1194 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
1195"""
1196def register (obj):
1197 if obj == None:
1198 obj = gdb
1199
1200 # Wire up the pretty-printer
1201 obj.pretty_printers.append(pretty_printer_lookup)
1202
1203register (gdb.current_objfile ())
1204
1205
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001206
1207# Unfortunately, the exact API exposed by the gdb module varies somewhat
1208# from build to build
1209# See http://bugs.python.org/issue8279?#msg102276
1210
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001211class Frame(object):
1212 '''
1213 Wrapper for gdb.Frame, adding various methods
1214 '''
1215 def __init__(self, gdbframe):
1216 self._gdbframe = gdbframe
1217
1218 def older(self):
1219 older = self._gdbframe.older()
1220 if older:
1221 return Frame(older)
1222 else:
1223 return None
1224
1225 def newer(self):
1226 newer = self._gdbframe.newer()
1227 if newer:
1228 return Frame(newer)
1229 else:
1230 return None
1231
1232 def select(self):
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001233 '''If supported, select this frame and return True; return False if unsupported
1234
1235 Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
1236 onwards, but absent on Ubuntu buildbot'''
1237 if not hasattr(self._gdbframe, 'select'):
1238 print ('Unable to select frame: '
1239 'this build of gdb does not expose a gdb.Frame.select method')
1240 return False
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001241 self._gdbframe.select()
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001242 return True
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001243
1244 def get_index(self):
1245 '''Calculate index of frame, starting at 0 for the newest frame within
1246 this thread'''
1247 index = 0
1248 # Go down until you reach the newest frame:
1249 iter_frame = self
1250 while iter_frame.newer():
1251 index += 1
1252 iter_frame = iter_frame.newer()
1253 return index
1254
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001255 # We divide frames into:
1256 # - "python frames":
1257 # - "bytecode frames" i.e. PyEval_EvalFrameEx
1258 # - "other python frames": things that are of interest from a python
1259 # POV, but aren't bytecode (e.g. GC, GIL)
1260 # - everything else
1261
1262 def is_python_frame(self):
1263 '''Is this a PyEval_EvalFrameEx frame, or some other important
1264 frame? (see is_other_python_frame for what "important" means in this
1265 context)'''
1266 if self.is_evalframeex():
1267 return True
1268 if self.is_other_python_frame():
1269 return True
1270 return False
1271
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001272 def is_evalframeex(self):
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001273 '''Is this a PyEval_EvalFrameEx frame?'''
Victor Stinnera92e81b2010-04-20 22:28:31 +00001274 if self._gdbframe.name() == 'PyEval_EvalFrameEx':
1275 '''
1276 I believe we also need to filter on the inline
1277 struct frame_id.inline_depth, only regarding frames with
1278 an inline depth of 0 as actually being this function
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001279
Victor Stinnera92e81b2010-04-20 22:28:31 +00001280 So we reject those with type gdb.INLINE_FRAME
1281 '''
1282 if self._gdbframe.type() == gdb.NORMAL_FRAME:
1283 # We have a PyEval_EvalFrameEx frame:
1284 return True
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001285
1286 return False
1287
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001288 def is_other_python_frame(self):
1289 '''Is this frame worth displaying in python backtraces?
1290 Examples:
1291 - waiting on the GIL
1292 - garbage-collecting
1293 - within a CFunction
1294 If it is, return a descriptive string
1295 For other frames, return False
1296 '''
1297 if self.is_waiting_for_gil():
1298 return 'Waiting for the GIL'
1299 elif self.is_gc_collect():
1300 return 'Garbage-collecting'
1301 else:
1302 # Detect invocations of PyCFunction instances:
1303 older = self.older()
1304 if older and older._gdbframe.name() == 'PyCFunction_Call':
1305 # Within that frame:
1306 # "func" is the local containing the PyObject* of the
1307 # PyCFunctionObject instance
1308 # "f" is the same value, but cast to (PyCFunctionObject*)
1309 # "self" is the (PyObject*) of the 'self'
1310 try:
1311 # Use the prettyprinter for the func:
1312 func = older._gdbframe.read_var('func')
1313 return str(func)
1314 except RuntimeError:
1315 return 'PyCFunction invocation (unable to read "func")'
1316
1317 # This frame isn't worth reporting:
1318 return False
1319
1320 def is_waiting_for_gil(self):
1321 '''Is this frame waiting on the GIL?'''
1322 # This assumes the _POSIX_THREADS version of Python/ceval_gil.h:
1323 name = self._gdbframe.name()
1324 if name:
1325 return ('PyThread_acquire_lock' in name
1326 and 'lock_PyThread_acquire_lock' not in name)
1327
1328 def is_gc_collect(self):
1329 '''Is this frame "collect" within the garbage-collector?'''
1330 return self._gdbframe.name() == 'collect'
1331
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001332 def get_pyop(self):
1333 try:
1334 f = self._gdbframe.read_var('f')
Victor Stinner99cff3f2011-12-19 13:59:58 +01001335 frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1336 if not frame.is_optimized_out():
1337 return frame
1338 # gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
1339 # because it was "optimized out". Try to get "f" from the frame
1340 # of the caller, PyEval_EvalCodeEx().
1341 orig_frame = frame
1342 caller = self._gdbframe.older()
1343 if caller:
1344 f = caller.read_var('f')
1345 frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1346 if not frame.is_optimized_out():
1347 return frame
1348 return orig_frame
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001349 except ValueError:
1350 return None
1351
1352 @classmethod
1353 def get_selected_frame(cls):
1354 _gdbframe = gdb.selected_frame()
1355 if _gdbframe:
1356 return Frame(_gdbframe)
1357 return None
1358
1359 @classmethod
1360 def get_selected_python_frame(cls):
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001361 '''Try to obtain the Frame for the python-related code in the selected
1362 frame, or None'''
1363 frame = cls.get_selected_frame()
1364
1365 while frame:
1366 if frame.is_python_frame():
1367 return frame
1368 frame = frame.older()
1369
1370 # Not found:
1371 return None
1372
1373 @classmethod
1374 def get_selected_bytecode_frame(cls):
1375 '''Try to obtain the Frame for the python bytecode interpreter in the
1376 selected GDB frame, or None'''
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001377 frame = cls.get_selected_frame()
1378
1379 while frame:
1380 if frame.is_evalframeex():
1381 return frame
1382 frame = frame.older()
1383
1384 # Not found:
1385 return None
1386
1387 def print_summary(self):
1388 if self.is_evalframeex():
1389 pyop = self.get_pyop()
1390 if pyop:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001391 line = pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1392 write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line))
Victor Stinner99cff3f2011-12-19 13:59:58 +01001393 if not pyop.is_optimized_out():
1394 line = pyop.current_line()
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001395 if line is not None:
1396 sys.stdout.write(' %s\n' % line.strip())
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001397 else:
1398 sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1399 else:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001400 info = self.is_other_python_frame()
1401 if info:
1402 sys.stdout.write('#%i %s\n' % (self.get_index(), info))
1403 else:
1404 sys.stdout.write('#%i\n' % self.get_index())
1405
1406 def print_traceback(self):
1407 if self.is_evalframeex():
1408 pyop = self.get_pyop()
1409 if pyop:
1410 pyop.print_traceback()
1411 if not pyop.is_optimized_out():
1412 line = pyop.current_line()
1413 if line is not None:
1414 sys.stdout.write(' %s\n' % line.strip())
1415 else:
1416 sys.stdout.write(' (unable to read python frame information)\n')
1417 else:
1418 info = self.is_other_python_frame()
1419 if info:
1420 sys.stdout.write(' %s\n' % info)
1421 else:
1422 sys.stdout.write(' (not a python frame)\n')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001423
1424class PyList(gdb.Command):
1425 '''List the current Python source code, if any
1426
1427 Use
1428 py-list START
1429 to list at a different line number within the python source.
1430
1431 Use
1432 py-list START, END
1433 to list a specific range of lines within the python source.
1434 '''
1435
1436 def __init__(self):
1437 gdb.Command.__init__ (self,
1438 "py-list",
1439 gdb.COMMAND_FILES,
1440 gdb.COMPLETE_NONE)
1441
1442
1443 def invoke(self, args, from_tty):
1444 import re
1445
1446 start = None
1447 end = None
1448
1449 m = re.match(r'\s*(\d+)\s*', args)
1450 if m:
1451 start = int(m.group(0))
1452 end = start + 10
1453
1454 m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
1455 if m:
1456 start, end = map(int, m.groups())
1457
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001458 # py-list requires an actual PyEval_EvalFrameEx frame:
1459 frame = Frame.get_selected_bytecode_frame()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001460 if not frame:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001461 print('Unable to locate gdb frame for python bytecode interpreter')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001462 return
1463
1464 pyop = frame.get_pyop()
Victor Stinner99cff3f2011-12-19 13:59:58 +01001465 if not pyop or pyop.is_optimized_out():
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001466 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001467 return
1468
1469 filename = pyop.filename()
1470 lineno = pyop.current_line_num()
1471
1472 if start is None:
1473 start = lineno - 5
1474 end = lineno + 5
1475
1476 if start<1:
1477 start = 1
1478
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001479 try:
1480 f = open(filename, 'r')
1481 except IOError as err:
1482 sys.stdout.write('Unable to open %s: %s\n'
1483 % (filename, err))
1484 return
1485 with f:
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001486 all_lines = f.readlines()
1487 # start and end are 1-based, all_lines is 0-based;
1488 # so [start-1:end] as a python slice gives us [start, end] as a
1489 # closed interval
1490 for i, line in enumerate(all_lines[start-1:end]):
1491 linestr = str(i+start)
1492 # Highlight current line:
1493 if i + start == lineno:
1494 linestr = '>' + linestr
1495 sys.stdout.write('%4s %s' % (linestr, line))
1496
1497
1498# ...and register the command:
1499PyList()
1500
1501def move_in_stack(move_up):
1502 '''Move up or down the stack (for the py-up/py-down command)'''
1503 frame = Frame.get_selected_python_frame()
1504 while frame:
1505 if move_up:
1506 iter_frame = frame.older()
1507 else:
1508 iter_frame = frame.newer()
1509
1510 if not iter_frame:
1511 break
1512
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001513 if iter_frame.is_python_frame():
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001514 # Result:
Martin v. Löwis24f09fd2010-04-17 22:40:40 +00001515 if iter_frame.select():
1516 iter_frame.print_summary()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001517 return
1518
1519 frame = iter_frame
1520
1521 if move_up:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001522 print('Unable to find an older python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001523 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001524 print('Unable to find a newer python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001525
1526class PyUp(gdb.Command):
1527 'Select and print the python stack frame that called this one (if any)'
1528 def __init__(self):
1529 gdb.Command.__init__ (self,
1530 "py-up",
1531 gdb.COMMAND_STACK,
1532 gdb.COMPLETE_NONE)
1533
1534
1535 def invoke(self, args, from_tty):
1536 move_in_stack(move_up=True)
1537
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001538class PyDown(gdb.Command):
1539 'Select and print the python stack frame called by this one (if any)'
1540 def __init__(self):
1541 gdb.Command.__init__ (self,
1542 "py-down",
1543 gdb.COMMAND_STACK,
1544 gdb.COMPLETE_NONE)
1545
1546
1547 def invoke(self, args, from_tty):
1548 move_in_stack(move_up=False)
1549
Victor Stinnera92e81b2010-04-20 22:28:31 +00001550# Not all builds of gdb have gdb.Frame.select
1551if hasattr(gdb.Frame, 'select'):
1552 PyUp()
1553 PyDown()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001554
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001555class PyBacktraceFull(gdb.Command):
1556 'Display the current python frame and all the frames within its call stack (if any)'
1557 def __init__(self):
1558 gdb.Command.__init__ (self,
1559 "py-bt-full",
1560 gdb.COMMAND_STACK,
1561 gdb.COMPLETE_NONE)
1562
1563
1564 def invoke(self, args, from_tty):
1565 frame = Frame.get_selected_python_frame()
1566 while frame:
1567 if frame.is_python_frame():
1568 frame.print_summary()
1569 frame = frame.older()
1570
1571PyBacktraceFull()
1572
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001573class PyBacktrace(gdb.Command):
1574 'Display the current python frame and all the frames within its call stack (if any)'
1575 def __init__(self):
1576 gdb.Command.__init__ (self,
1577 "py-bt",
1578 gdb.COMMAND_STACK,
1579 gdb.COMPLETE_NONE)
1580
1581
1582 def invoke(self, args, from_tty):
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001583 sys.stdout.write('Traceback (most recent call first):\n')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001584 frame = Frame.get_selected_python_frame()
1585 while frame:
Victor Stinnercc1db4b2015-09-03 10:17:28 +02001586 if frame.is_python_frame():
1587 frame.print_traceback()
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001588 frame = frame.older()
1589
1590PyBacktrace()
1591
1592class PyPrint(gdb.Command):
1593 'Look up the given python variable name, and print it'
1594 def __init__(self):
1595 gdb.Command.__init__ (self,
1596 "py-print",
1597 gdb.COMMAND_DATA,
1598 gdb.COMPLETE_NONE)
1599
1600
1601 def invoke(self, args, from_tty):
1602 name = str(args)
1603
1604 frame = Frame.get_selected_python_frame()
1605 if not frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001606 print('Unable to locate python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001607 return
1608
1609 pyop_frame = frame.get_pyop()
1610 if not pyop_frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001611 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001612 return
1613
1614 pyop_var, scope = pyop_frame.get_var_by_name(name)
1615
1616 if pyop_var:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001617 print('%s %r = %s'
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001618 % (scope,
1619 name,
1620 pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
1621 else:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001622 print('%r not found' % name)
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001623
1624PyPrint()
1625
1626class PyLocals(gdb.Command):
1627 'Look up the given python variable name, and print it'
1628 def __init__(self):
1629 gdb.Command.__init__ (self,
1630 "py-locals",
1631 gdb.COMMAND_DATA,
1632 gdb.COMPLETE_NONE)
1633
1634
1635 def invoke(self, args, from_tty):
1636 name = str(args)
1637
1638 frame = Frame.get_selected_python_frame()
1639 if not frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001640 print('Unable to locate python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001641 return
1642
1643 pyop_frame = frame.get_pyop()
1644 if not pyop_frame:
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001645 print('Unable to read information on python frame')
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001646 return
1647
1648 for pyop_name, pyop_value in pyop_frame.iter_locals():
Antoine Pitrou358da5b2013-11-23 17:40:36 +01001649 print('%s = %s'
Martin v. Löwisbf0dfb32010-04-01 07:40:51 +00001650 % (pyop_name.proxyval(set()),
1651 pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
1652
1653PyLocals()