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