blob: 6ed608721f25f2d7c1c960d1125fd7bbd2cf9175 [file] [log] [blame]
Benjamin Peterson6a6666a2010-04-11 21:49:28 +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*
Victor Stinner67df3a42010-04-21 13:53:05 +000022holding three PyObject* that turn out to be PyBytesObject* instances, we can
Martin v. Löwis5ae68102010-04-21 22:38:42 +000023generate a proxy value within the gdb process that is a list of bytes
24instances:
25 [b"foo", b"bar", b"baz"]
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000026
27Doing so can be expensive for complicated graphs of objects, and could take
28some time, so we also have a "write_repr" method that writes a representation
29of the data to a file-like object. This allows us to stop the traversal by
30having the file-like object raise an exception if it gets too much data.
31
32With both "proxyval" and "write_repr" we keep track of the set of all addresses
33visited so far in the traversal, to avoid infinite recursion due to cycles in
34the graph of object references.
35
36We try to defer gdb.lookup_type() invocations for python types until as late as
37possible: for a dynamically linked python binary, when the process starts in
38the debugger, the libpython.so hasn't been dynamically loaded yet, so none of
39the type names are known to the debugger
40
41The module also extends gdb with some python-specific commands.
42'''
43from __future__ import with_statement
44import gdb
Victor Stinner150016f2010-05-19 23:04:56 +000045import locale
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000046
47# Look up the gdb.Type for some standard types:
48_type_char_ptr = gdb.lookup_type('char').pointer() # char*
49_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
50_type_void_ptr = gdb.lookup_type('void').pointer() # void*
51_type_size_t = gdb.lookup_type('size_t')
52
53SIZEOF_VOID_P = _type_void_ptr.sizeof
54
55
56Py_TPFLAGS_HEAPTYPE = (1L << 9)
57
58Py_TPFLAGS_INT_SUBCLASS = (1L << 23)
59Py_TPFLAGS_LONG_SUBCLASS = (1L << 24)
60Py_TPFLAGS_LIST_SUBCLASS = (1L << 25)
61Py_TPFLAGS_TUPLE_SUBCLASS = (1L << 26)
Martin v. Löwis5ae68102010-04-21 22:38:42 +000062Py_TPFLAGS_BYTES_SUBCLASS = (1L << 27)
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000063Py_TPFLAGS_UNICODE_SUBCLASS = (1L << 28)
64Py_TPFLAGS_DICT_SUBCLASS = (1L << 29)
65Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30)
66Py_TPFLAGS_TYPE_SUBCLASS = (1L << 31)
67
68
69MAX_OUTPUT_LEN=1024
70
Martin v. Löwis5ae68102010-04-21 22:38:42 +000071hexdigits = "0123456789abcdef"
72
Victor Stinner150016f2010-05-19 23:04:56 +000073ENCODING = locale.getpreferredencoding()
Martin v. Löwis5ae68102010-04-21 22:38:42 +000074
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000075class NullPyObjectPtr(RuntimeError):
76 pass
77
78
79def safety_limit(val):
80 # Given a integer value from the process being debugged, limit it to some
81 # safety threshold so that arbitrary breakage within said process doesn't
82 # break the gdb process too much (e.g. sizes of iterations, sizes of lists)
83 return min(val, 1000)
84
85
86def safe_range(val):
87 # As per range, but don't trust the value too much: cap it to a safety
88 # threshold in case the data was corrupted
89 return xrange(safety_limit(val))
90
91
92class StringTruncated(RuntimeError):
93 pass
94
95class TruncatedStringIO(object):
96 '''Similar to cStringIO, but can truncate the output by raising a
97 StringTruncated exception'''
98 def __init__(self, maxlen=None):
99 self._val = ''
100 self.maxlen = maxlen
101
102 def write(self, data):
103 if self.maxlen:
104 if len(data) + len(self._val) > self.maxlen:
105 # Truncation:
106 self._val += data[0:self.maxlen - len(self._val)]
107 raise StringTruncated()
108
109 self._val += data
110
111 def getvalue(self):
112 return self._val
113
114class PyObjectPtr(object):
115 """
116 Class wrapping a gdb.Value that's a either a (PyObject*) within the
Victor Stinner67df3a42010-04-21 13:53:05 +0000117 inferior process, or some subclass pointer e.g. (PyBytesObject*)
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000118
119 There will be a subclass for every refined PyObject type that we care
120 about.
121
122 Note that at every stage the underlying pointer could be NULL, point
123 to corrupt data, etc; this is the debugger, after all.
124 """
125 _typename = 'PyObject'
126
127 def __init__(self, gdbval, cast_to=None):
128 if cast_to:
129 self._gdbval = gdbval.cast(cast_to)
130 else:
131 self._gdbval = gdbval
132
133 def field(self, name):
134 '''
135 Get the gdb.Value for the given field within the PyObject, coping with
136 some python 2 versus python 3 differences.
137
138 Various libpython types are defined using the "PyObject_HEAD" and
139 "PyObject_VAR_HEAD" macros.
140
141 In Python 2, this these are defined so that "ob_type" and (for a var
142 object) "ob_size" are fields of the type in question.
143
144 In Python 3, this is defined as an embedded PyVarObject type thus:
145 PyVarObject ob_base;
146 so that the "ob_size" field is located insize the "ob_base" field, and
147 the "ob_type" is most easily accessed by casting back to a (PyObject*).
148 '''
149 if self.is_null():
150 raise NullPyObjectPtr(self)
151
152 if name == 'ob_type':
153 pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type())
154 return pyo_ptr.dereference()[name]
155
156 if name == 'ob_size':
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000157 pyo_ptr = self._gdbval.cast(PyVarObjectPtr.get_gdb_type())
158 return pyo_ptr.dereference()[name]
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000159
160 # General case: look it up inside the object:
161 return self._gdbval.dereference()[name]
162
163 def pyop_field(self, name):
164 '''
165 Get a PyObjectPtr for the given PyObject* field within this PyObject,
166 coping with some python 2 versus python 3 differences.
167 '''
168 return PyObjectPtr.from_pyobject_ptr(self.field(name))
169
170 def write_field_repr(self, name, out, visited):
171 '''
172 Extract the PyObject* field named "name", and write its representation
173 to file-like object "out"
174 '''
175 field_obj = self.pyop_field(name)
176 field_obj.write_repr(out, visited)
177
178 def get_truncated_repr(self, maxlen):
179 '''
180 Get a repr-like string for the data, but truncate it at "maxlen" bytes
181 (ending the object graph traversal as soon as you do)
182 '''
183 out = TruncatedStringIO(maxlen)
184 try:
185 self.write_repr(out, set())
186 except StringTruncated:
187 # Truncation occurred:
188 return out.getvalue() + '...(truncated)'
189
190 # No truncation occurred:
191 return out.getvalue()
192
193 def type(self):
194 return PyTypeObjectPtr(self.field('ob_type'))
195
196 def is_null(self):
197 return 0 == long(self._gdbval)
198
199 def is_optimized_out(self):
200 '''
201 Is the value of the underlying PyObject* visible to the debugger?
202
203 This can vary with the precise version of the compiler used to build
204 Python, and the precise version of gdb.
205
206 See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with
207 PyEval_EvalFrameEx's "f"
208 '''
209 return self._gdbval.is_optimized_out
210
211 def safe_tp_name(self):
212 try:
213 return self.type().field('tp_name').string()
214 except NullPyObjectPtr:
215 # NULL tp_name?
216 return 'unknown'
217 except RuntimeError:
218 # Can't even read the object at all?
219 return 'unknown'
220
221 def proxyval(self, visited):
222 '''
223 Scrape a value from the inferior process, and try to represent it
224 within the gdb process, whilst (hopefully) avoiding crashes when
225 the remote data is corrupt.
226
227 Derived classes will override this.
228
229 For example, a PyIntObject* with ob_ival 42 in the inferior process
230 should result in an int(42) in this process.
231
232 visited: a set of all gdb.Value pyobject pointers already visited
233 whilst generating this value (to guard against infinite recursion when
234 visiting object graphs with loops). Analogous to Py_ReprEnter and
235 Py_ReprLeave
236 '''
237
238 class FakeRepr(object):
239 """
240 Class representing a non-descript PyObject* value in the inferior
241 process for when we don't have a custom scraper, intended to have
242 a sane repr().
243 """
244
245 def __init__(self, tp_name, address):
246 self.tp_name = tp_name
247 self.address = address
248
249 def __repr__(self):
250 # For the NULL pointer, we have no way of knowing a type, so
251 # special-case it as per
252 # http://bugs.python.org/issue8032#msg100882
253 if self.address == 0:
254 return '0x0'
255 return '<%s at remote 0x%x>' % (self.tp_name, self.address)
256
257 return FakeRepr(self.safe_tp_name(),
258 long(self._gdbval))
259
260 def write_repr(self, out, visited):
261 '''
262 Write a string representation of the value scraped from the inferior
263 process to "out", a file-like object.
264 '''
265 # Default implementation: generate a proxy value and write its repr
266 # However, this could involve a lot of work for complicated objects,
267 # so for derived classes we specialize this
268 return out.write(repr(self.proxyval(visited)))
269
270 @classmethod
271 def subclass_from_type(cls, t):
272 '''
273 Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
274 (PyTypeObject*), determine the corresponding subclass of PyObjectPtr
275 to use
276
277 Ideally, we would look up the symbols for the global types, but that
278 isn't working yet:
279 (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
280 Traceback (most recent call last):
281 File "<string>", line 1, in <module>
282 NotImplementedError: Symbol type not yet supported in Python scripts.
283 Error while executing Python code.
284
285 For now, we use tp_flags, after doing some string comparisons on the
286 tp_name for some special-cases that don't seem to be visible through
287 flags
288 '''
289 try:
290 tp_name = t.field('tp_name').string()
291 tp_flags = int(t.field('tp_flags'))
292 except RuntimeError:
293 # Handle any kind of error e.g. NULL ptrs by simply using the base
294 # class
295 return cls
296
297 #print 'tp_flags = 0x%08x' % tp_flags
298 #print 'tp_name = %r' % tp_name
299
300 name_map = {'bool': PyBoolObjectPtr,
301 'classobj': PyClassObjectPtr,
302 'instance': PyInstanceObjectPtr,
303 'NoneType': PyNoneStructPtr,
304 'frame': PyFrameObjectPtr,
305 'set' : PySetObjectPtr,
306 'frozenset' : PySetObjectPtr,
307 'builtin_function_or_method' : PyCFunctionObjectPtr,
308 }
309 if tp_name in name_map:
310 return name_map[tp_name]
311
312 if tp_flags & Py_TPFLAGS_HEAPTYPE:
313 return HeapTypeObjectPtr
314
315 if tp_flags & Py_TPFLAGS_INT_SUBCLASS:
316 return PyIntObjectPtr
317 if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
318 return PyLongObjectPtr
319 if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
320 return PyListObjectPtr
321 if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
322 return PyTupleObjectPtr
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000323 if tp_flags & Py_TPFLAGS_BYTES_SUBCLASS:
Victor Stinner67df3a42010-04-21 13:53:05 +0000324 return PyBytesObjectPtr
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000325 if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
326 return PyUnicodeObjectPtr
327 if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
328 return PyDictObjectPtr
329 if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
330 return PyBaseExceptionObjectPtr
331 #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
332 # return PyTypeObjectPtr
333
334 # Use the base class:
335 return cls
336
337 @classmethod
338 def from_pyobject_ptr(cls, gdbval):
339 '''
340 Try to locate the appropriate derived class dynamically, and cast
341 the pointer accordingly.
342 '''
343 try:
344 p = PyObjectPtr(gdbval)
345 cls = cls.subclass_from_type(p.type())
346 return cls(gdbval, cast_to=cls.get_gdb_type())
347 except RuntimeError:
348 # Handle any kind of error e.g. NULL ptrs by simply using the base
349 # class
350 pass
351 return cls(gdbval)
352
353 @classmethod
354 def get_gdb_type(cls):
355 return gdb.lookup_type(cls._typename).pointer()
356
357 def as_address(self):
358 return long(self._gdbval)
359
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000360class PyVarObjectPtr(PyObjectPtr):
361 _typename = 'PyVarObject'
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000362
363class ProxyAlreadyVisited(object):
364 '''
365 Placeholder proxy to use when protecting against infinite recursion due to
366 loops in the object graph.
367
368 Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
369 '''
370 def __init__(self, rep):
371 self._rep = rep
372
373 def __repr__(self):
374 return self._rep
375
376
377def _write_instance_repr(out, visited, name, pyop_attrdict, address):
378 '''Shared code for use by old-style and new-style classes:
379 write a representation to file-like object "out"'''
380 out.write('<')
381 out.write(name)
382
383 # Write dictionary of instance attributes:
384 if isinstance(pyop_attrdict, PyDictObjectPtr):
385 out.write('(')
386 first = True
387 for pyop_arg, pyop_val in pyop_attrdict.iteritems():
388 if not first:
389 out.write(', ')
390 first = False
391 out.write(pyop_arg.proxyval(visited))
392 out.write('=')
393 pyop_val.write_repr(out, visited)
394 out.write(')')
395 out.write(' at remote 0x%x>' % address)
396
397
398class InstanceProxy(object):
399
400 def __init__(self, cl_name, attrdict, address):
401 self.cl_name = cl_name
402 self.attrdict = attrdict
403 self.address = address
404
405 def __repr__(self):
406 if isinstance(self.attrdict, dict):
407 kwargs = ', '.join(["%s=%r" % (arg, val)
408 for arg, val in self.attrdict.iteritems()])
409 return '<%s(%s) at remote 0x%x>' % (self.cl_name,
410 kwargs, self.address)
411 else:
412 return '<%s at remote 0x%x>' % (self.cl_name,
413 self.address)
414
415def _PyObject_VAR_SIZE(typeobj, nitems):
416 return ( ( typeobj.field('tp_basicsize') +
417 nitems * typeobj.field('tp_itemsize') +
418 (SIZEOF_VOID_P - 1)
419 ) & ~(SIZEOF_VOID_P - 1)
420 ).cast(_type_size_t)
421
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
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000522class PyClassObjectPtr(PyObjectPtr):
523 """
524 Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
525 instance within the process being debugged.
526 """
527 _typename = 'PyClassObject'
528
529
530class BuiltInFunctionProxy(object):
531 def __init__(self, ml_name):
532 self.ml_name = ml_name
533
534 def __repr__(self):
535 return "<built-in function %s>" % self.ml_name
536
537class BuiltInMethodProxy(object):
538 def __init__(self, ml_name, pyop_m_self):
539 self.ml_name = ml_name
540 self.pyop_m_self = pyop_m_self
541
542 def __repr__(self):
543 return ('<built-in method %s of %s object at remote 0x%x>'
544 % (self.ml_name,
545 self.pyop_m_self.safe_tp_name(),
546 self.pyop_m_self.as_address())
547 )
548
549class PyCFunctionObjectPtr(PyObjectPtr):
550 """
551 Class wrapping a gdb.Value that's a PyCFunctionObject*
552 (see Include/methodobject.h and Objects/methodobject.c)
553 """
554 _typename = 'PyCFunctionObject'
555
556 def proxyval(self, visited):
557 m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
558 ml_name = m_ml['ml_name'].string()
559
560 pyop_m_self = self.pyop_field('m_self')
561 if pyop_m_self.is_null():
562 return BuiltInFunctionProxy(ml_name)
563 else:
564 return BuiltInMethodProxy(ml_name, pyop_m_self)
565
566
567class PyCodeObjectPtr(PyObjectPtr):
568 """
569 Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance
570 within the process being debugged.
571 """
572 _typename = 'PyCodeObject'
573
574 def addr2line(self, addrq):
575 '''
576 Get the line number for a given bytecode offset
577
578 Analogous to PyCode_Addr2Line; translated from pseudocode in
579 Objects/lnotab_notes.txt
580 '''
581 co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
582
583 # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
584 # not 0, as lnotab_notes.txt has it:
585 lineno = int_from_int(self.field('co_firstlineno'))
586
587 addr = 0
588 for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
589 addr += ord(addr_incr)
590 if addr > addrq:
591 return lineno
592 lineno += ord(line_incr)
593 return lineno
594
595
596class PyDictObjectPtr(PyObjectPtr):
597 """
598 Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
599 within the process being debugged.
600 """
601 _typename = 'PyDictObject'
602
603 def iteritems(self):
604 '''
605 Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
606 analagous to dict.iteritems()
607 '''
608 for i in safe_range(self.field('ma_mask') + 1):
609 ep = self.field('ma_table') + i
610 pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
611 if not pyop_value.is_null():
612 pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
613 yield (pyop_key, pyop_value)
614
615 def proxyval(self, visited):
616 # Guard against infinite loops:
617 if self.as_address() in visited:
618 return ProxyAlreadyVisited('{...}')
619 visited.add(self.as_address())
620
621 result = {}
622 for pyop_key, pyop_value in self.iteritems():
623 proxy_key = pyop_key.proxyval(visited)
624 proxy_value = pyop_value.proxyval(visited)
625 result[proxy_key] = proxy_value
626 return result
627
628 def write_repr(self, out, visited):
629 # Guard against infinite loops:
630 if self.as_address() in visited:
631 out.write('{...}')
632 return
633 visited.add(self.as_address())
634
635 out.write('{')
636 first = True
637 for pyop_key, pyop_value in self.iteritems():
638 if not first:
639 out.write(', ')
640 first = False
641 pyop_key.write_repr(out, visited)
642 out.write(': ')
643 pyop_value.write_repr(out, visited)
644 out.write('}')
645
646class PyInstanceObjectPtr(PyObjectPtr):
647 _typename = 'PyInstanceObject'
648
649 def proxyval(self, visited):
650 # Guard against infinite loops:
651 if self.as_address() in visited:
652 return ProxyAlreadyVisited('<...>')
653 visited.add(self.as_address())
654
655 # Get name of class:
656 in_class = self.pyop_field('in_class')
657 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
658
659 # Get dictionary of instance attributes:
660 in_dict = self.pyop_field('in_dict').proxyval(visited)
661
662 # Old-style class:
663 return InstanceProxy(cl_name, in_dict, long(self._gdbval))
664
665 def write_repr(self, out, visited):
666 # Guard against infinite loops:
667 if self.as_address() in visited:
668 out.write('<...>')
669 return
670 visited.add(self.as_address())
671
672 # Old-style class:
673
674 # Get name of class:
675 in_class = self.pyop_field('in_class')
676 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
677
678 # Get dictionary of instance attributes:
679 pyop_in_dict = self.pyop_field('in_dict')
680
681 _write_instance_repr(out, visited,
682 cl_name, pyop_in_dict, self.as_address())
683
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000684class PyListObjectPtr(PyObjectPtr):
685 _typename = 'PyListObject'
686
687 def __getitem__(self, i):
688 # Get the gdb.Value for the (PyObject*) with the given index:
689 field_ob_item = self.field('ob_item')
690 return field_ob_item[i]
691
692 def proxyval(self, visited):
693 # Guard against infinite loops:
694 if self.as_address() in visited:
695 return ProxyAlreadyVisited('[...]')
696 visited.add(self.as_address())
697
698 result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
699 for i in safe_range(int_from_int(self.field('ob_size')))]
700 return result
701
702 def write_repr(self, out, visited):
703 # Guard against infinite loops:
704 if self.as_address() in visited:
705 out.write('[...]')
706 return
707 visited.add(self.as_address())
708
709 out.write('[')
710 for i in safe_range(int_from_int(self.field('ob_size'))):
711 if i > 0:
712 out.write(', ')
713 element = PyObjectPtr.from_pyobject_ptr(self[i])
714 element.write_repr(out, visited)
715 out.write(']')
716
717class PyLongObjectPtr(PyObjectPtr):
718 _typename = 'PyLongObject'
719
720 def proxyval(self, visited):
721 '''
722 Python's Include/longobjrep.h has this declaration:
723 struct _longobject {
724 PyObject_VAR_HEAD
725 digit ob_digit[1];
726 };
727
728 with this description:
729 The absolute value of a number is equal to
730 SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
731 Negative numbers are represented with ob_size < 0;
732 zero is represented by ob_size == 0.
733
734 where SHIFT can be either:
735 #define PyLong_SHIFT 30
736 #define PyLong_SHIFT 15
737 '''
738 ob_size = long(self.field('ob_size'))
739 if ob_size == 0:
740 return 0L
741
742 ob_digit = self.field('ob_digit')
743
744 if gdb.lookup_type('digit').sizeof == 2:
745 SHIFT = 15L
746 else:
747 SHIFT = 30L
748
749 digits = [long(ob_digit[i]) * 2**(SHIFT*i)
750 for i in safe_range(abs(ob_size))]
751 result = sum(digits)
752 if ob_size < 0:
753 result = -result
754 return result
755
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000756 def write_repr(self, out, visited):
757 # Write this out as a Python 3 int literal, i.e. without the "L" suffix
758 proxy = self.proxyval(visited)
759 out.write("%s" % proxy)
760
761
762class PyBoolObjectPtr(PyLongObjectPtr):
763 """
764 Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
765 <bool> instances (Py_True/Py_False) within the process being debugged.
766 """
767 def proxyval(self, visited):
768 if PyLongObjectPtr.proxyval(self, visited):
769 return True
770 else:
771 return False
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000772
773class PyNoneStructPtr(PyObjectPtr):
774 """
775 Class wrapping a gdb.Value that's a PyObject* pointing to the
776 singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
777 """
778 _typename = 'PyObject'
779
780 def proxyval(self, visited):
781 return None
782
783
784class PyFrameObjectPtr(PyObjectPtr):
785 _typename = 'PyFrameObject'
786
787 def __init__(self, gdbval, cast_to):
788 PyObjectPtr.__init__(self, gdbval, cast_to)
789
790 if not self.is_optimized_out():
791 self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
792 self.co_name = self.co.pyop_field('co_name')
793 self.co_filename = self.co.pyop_field('co_filename')
794
795 self.f_lineno = int_from_int(self.field('f_lineno'))
796 self.f_lasti = int_from_int(self.field('f_lasti'))
797 self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
798 self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
799
800 def iter_locals(self):
801 '''
802 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
803 the local variables of this frame
804 '''
805 if self.is_optimized_out():
806 return
807
808 f_localsplus = self.field('f_localsplus')
809 for i in safe_range(self.co_nlocals):
810 pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
811 if not pyop_value.is_null():
812 pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
813 yield (pyop_name, pyop_value)
814
815 def iter_globals(self):
816 '''
817 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
818 the global variables of this frame
819 '''
820 if self.is_optimized_out():
821 return
822
823 pyop_globals = self.pyop_field('f_globals')
824 return pyop_globals.iteritems()
825
826 def iter_builtins(self):
827 '''
828 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
829 the builtin variables
830 '''
831 if self.is_optimized_out():
832 return
833
834 pyop_builtins = self.pyop_field('f_builtins')
835 return pyop_builtins.iteritems()
836
837 def get_var_by_name(self, name):
838 '''
839 Look for the named local variable, returning a (PyObjectPtr, scope) pair
840 where scope is a string 'local', 'global', 'builtin'
841
842 If not found, return (None, None)
843 '''
844 for pyop_name, pyop_value in self.iter_locals():
845 if name == pyop_name.proxyval(set()):
846 return pyop_value, 'local'
847 for pyop_name, pyop_value in self.iter_globals():
848 if name == pyop_name.proxyval(set()):
849 return pyop_value, 'global'
850 for pyop_name, pyop_value in self.iter_builtins():
851 if name == pyop_name.proxyval(set()):
852 return pyop_value, 'builtin'
853 return None, None
854
855 def filename(self):
856 '''Get the path of the current Python source file, as a string'''
857 if self.is_optimized_out():
858 return '(frame information optimized out)'
859 return self.co_filename.proxyval(set())
860
861 def current_line_num(self):
862 '''Get current line number as an integer (1-based)
863
864 Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
865
866 See Objects/lnotab_notes.txt
867 '''
868 if self.is_optimized_out():
869 return None
870 f_trace = self.field('f_trace')
871 if long(f_trace) != 0:
872 # we have a non-NULL f_trace:
873 return self.f_lineno
874 else:
875 #try:
876 return self.co.addr2line(self.f_lasti)
877 #except ValueError:
878 # return self.f_lineno
879
880 def current_line(self):
881 '''Get the text of the current source line as a string, with a trailing
882 newline character'''
883 if self.is_optimized_out():
884 return '(frame information optimized out)'
885 with open(self.filename(), 'r') as f:
886 all_lines = f.readlines()
887 # Convert from 1-based current_line_num to 0-based list offset:
888 return all_lines[self.current_line_num()-1]
889
890 def write_repr(self, out, visited):
891 if self.is_optimized_out():
892 out.write('(frame information optimized out)')
893 return
894 out.write('Frame 0x%x, for file %s, line %i, in %s ('
895 % (self.as_address(),
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000896 self.co_filename.proxyval(visited),
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000897 self.current_line_num(),
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000898 self.co_name.proxyval(visited)))
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000899 first = True
900 for pyop_name, pyop_value in self.iter_locals():
901 if not first:
902 out.write(', ')
903 first = False
904
905 out.write(pyop_name.proxyval(visited))
906 out.write('=')
907 pyop_value.write_repr(out, visited)
908
909 out.write(')')
910
911class PySetObjectPtr(PyObjectPtr):
912 _typename = 'PySetObject'
913
914 def proxyval(self, visited):
915 # Guard against infinite loops:
916 if self.as_address() in visited:
917 return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
918 visited.add(self.as_address())
919
920 members = []
921 table = self.field('table')
922 for i in safe_range(self.field('mask')+1):
923 setentry = table[i]
924 key = setentry['key']
925 if key != 0:
926 key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
927 if key_proxy != '<dummy key>':
928 members.append(key_proxy)
929 if self.safe_tp_name() == 'frozenset':
930 return frozenset(members)
931 else:
932 return set(members)
933
934 def write_repr(self, out, visited):
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000935 # Emulate Python 3's set_repr
936 tp_name = self.safe_tp_name()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000937
938 # Guard against infinite loops:
939 if self.as_address() in visited:
940 out.write('(...)')
941 return
942 visited.add(self.as_address())
943
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000944 # Python 3's set_repr special-cases the empty set:
945 if not self.field('used'):
946 out.write(tp_name)
947 out.write('()')
948 return
949
950 # Python 3 uses {} for set literals:
951 if tp_name != 'set':
952 out.write(tp_name)
953 out.write('(')
954
955 out.write('{')
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000956 first = True
957 table = self.field('table')
958 for i in safe_range(self.field('mask')+1):
959 setentry = table[i]
960 key = setentry['key']
961 if key != 0:
962 pyop_key = PyObjectPtr.from_pyobject_ptr(key)
963 key_proxy = pyop_key.proxyval(visited) # FIXME!
964 if key_proxy != '<dummy key>':
965 if not first:
966 out.write(', ')
967 first = False
968 pyop_key.write_repr(out, visited)
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000969 out.write('}')
970
971 if tp_name != 'set':
972 out.write(')')
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000973
974
Victor Stinner67df3a42010-04-21 13:53:05 +0000975class PyBytesObjectPtr(PyObjectPtr):
976 _typename = 'PyBytesObject'
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000977
978 def __str__(self):
979 field_ob_size = self.field('ob_size')
980 field_ob_sval = self.field('ob_sval')
981 char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr)
982 return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
983
984 def proxyval(self, visited):
985 return str(self)
986
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000987 def write_repr(self, out, visited):
988 # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix
989
990 # Get a PyStringObject* within the Python 2 gdb process:
991 proxy = self.proxyval(visited)
992
993 # Transliteration of Python 3's Objects/bytesobject.c:PyBytes_Repr
994 # to Python 2 code:
995 quote = "'"
996 if "'" in proxy and not '"' in proxy:
997 quote = '"'
998 out.write('b')
999 out.write(quote)
1000 for byte in proxy:
1001 if byte == quote or byte == '\\':
1002 out.write('\\')
1003 out.write(byte)
1004 elif byte == '\t':
1005 out.write('\\t')
1006 elif byte == '\n':
1007 out.write('\\n')
1008 elif byte == '\r':
1009 out.write('\\r')
1010 elif byte < ' ' or ord(byte) >= 0x7f:
1011 out.write('\\x')
1012 out.write(hexdigits[(ord(byte) & 0xf0) >> 4])
1013 out.write(hexdigits[ord(byte) & 0xf])
1014 else:
1015 out.write(byte)
1016 out.write(quote)
1017
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001018class PyTupleObjectPtr(PyObjectPtr):
1019 _typename = 'PyTupleObject'
1020
1021 def __getitem__(self, i):
1022 # Get the gdb.Value for the (PyObject*) with the given index:
1023 field_ob_item = self.field('ob_item')
1024 return field_ob_item[i]
1025
1026 def proxyval(self, visited):
1027 # Guard against infinite loops:
1028 if self.as_address() in visited:
1029 return ProxyAlreadyVisited('(...)')
1030 visited.add(self.as_address())
1031
1032 result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
1033 for i in safe_range(int_from_int(self.field('ob_size')))])
1034 return result
1035
1036 def write_repr(self, out, visited):
1037 # Guard against infinite loops:
1038 if self.as_address() in visited:
1039 out.write('(...)')
1040 return
1041 visited.add(self.as_address())
1042
1043 out.write('(')
1044 for i in safe_range(int_from_int(self.field('ob_size'))):
1045 if i > 0:
1046 out.write(', ')
1047 element = PyObjectPtr.from_pyobject_ptr(self[i])
1048 element.write_repr(out, visited)
1049 if self.field('ob_size') == 1:
1050 out.write(',)')
1051 else:
1052 out.write(')')
1053
1054class PyTypeObjectPtr(PyObjectPtr):
1055 _typename = 'PyTypeObject'
1056
1057
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001058def _unichr_is_printable(char):
1059 # Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
1060 if char == u" ":
1061 return True
1062 import unicodedata
1063 return unicodedata.category(char)[0] not in ("C", "Z")
1064
1065
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001066class PyUnicodeObjectPtr(PyObjectPtr):
1067 _typename = 'PyUnicodeObject'
1068
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001069 def char_width(self):
1070 _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
1071 return _type_Py_UNICODE.sizeof
1072
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001073 def proxyval(self, visited):
1074 # From unicodeobject.h:
1075 # Py_ssize_t length; /* Length of raw Unicode data in buffer */
1076 # Py_UNICODE *str; /* Raw Unicode buffer */
1077 field_length = long(self.field('length'))
1078 field_str = self.field('str')
1079
1080 # Gather a list of ints from the Py_UNICODE array; these are either
1081 # UCS-2 or UCS-4 code points:
1082 Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
1083
1084 # Convert the int code points to unicode characters, and generate a
1085 # local unicode instance:
1086 result = u''.join([unichr(ucs) for ucs in Py_UNICODEs])
1087 return result
1088
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001089 def write_repr(self, out, visited):
1090 # Write this out as a Python 3 str literal, i.e. without a "u" prefix
1091
1092 # Get a PyUnicodeObject* within the Python 2 gdb process:
1093 proxy = self.proxyval(visited)
1094
1095 # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr
1096 # to Python 2:
1097 if "'" in proxy and '"' not in proxy:
1098 quote = '"'
1099 else:
1100 quote = "'"
1101 out.write(quote)
1102
1103 i = 0
1104 while i < len(proxy):
1105 ch = proxy[i]
1106 i += 1
1107
1108 # Escape quotes and backslashes
1109 if ch == quote or ch == '\\':
1110 out.write('\\')
1111 out.write(ch)
1112
1113 # Map special whitespace to '\t', \n', '\r'
1114 elif ch == '\t':
1115 out.write('\\t')
1116 elif ch == '\n':
1117 out.write('\\n')
1118 elif ch == '\r':
1119 out.write('\\r')
1120
1121 # Map non-printable US ASCII to '\xhh' */
1122 elif ch < ' ' or ch == 0x7F:
1123 out.write('\\x')
1124 out.write(hexdigits[(ord(ch) >> 4) & 0x000F])
1125 out.write(hexdigits[ord(ch) & 0x000F])
1126
1127 # Copy ASCII characters as-is
1128 elif ord(ch) < 0x7F:
1129 out.write(ch)
1130
1131 # Non-ASCII characters
1132 else:
Victor Stinner150016f2010-05-19 23:04:56 +00001133 ucs = ch
1134 orig_ucs = None
1135 if self.char_width() == 2:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001136 # Get code point from surrogate pair
Victor Stinner150016f2010-05-19 23:04:56 +00001137 if (i < len(proxy)
1138 and 0xD800 <= ord(ch) < 0xDC00 \
1139 and 0xDC00 <= ord(proxy[i]) <= 0xDFFF):
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001140 ch2 = proxy[i]
Victor Stinner150016f2010-05-19 23:04:56 +00001141 code = (ord(ch) & 0x03FF) << 10
1142 code |= ord(ch2) & 0x03FF
1143 code += 0x00010000
1144 orig_ucs = ucs
1145 ucs = unichr(code)
1146 i += 1
1147 else:
1148 ch2 = None
1149
1150 printable = _unichr_is_printable(ucs)
1151 if printable:
1152 try:
1153 ucs.encode(ENCODING)
1154 except UnicodeEncodeError:
1155 printable = False
1156 if orig_ucs is not None:
1157 ucs = orig_ucs
1158 i -= 1
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001159
1160 # Map Unicode whitespace and control characters
1161 # (categories Z* and C* except ASCII space)
Victor Stinner150016f2010-05-19 23:04:56 +00001162 if not printable:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001163 # Unfortuately, Python 2's unicode type doesn't seem
1164 # to expose the "isprintable" method
Victor Stinner150016f2010-05-19 23:04:56 +00001165 code = ord(ucs)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001166
1167 # Map 8-bit characters to '\\xhh'
Victor Stinner150016f2010-05-19 23:04:56 +00001168 if code <= 0xff:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001169 out.write('\\x')
Victor Stinner150016f2010-05-19 23:04:56 +00001170 out.write(hexdigits[(code >> 4) & 0x000F])
1171 out.write(hexdigits[code & 0x000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001172 # Map 21-bit characters to '\U00xxxxxx'
Victor Stinner150016f2010-05-19 23:04:56 +00001173 elif code >= 0x10000:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001174 out.write('\\U')
Victor Stinner150016f2010-05-19 23:04:56 +00001175 out.write(hexdigits[(code >> 28) & 0x0000000F])
1176 out.write(hexdigits[(code >> 24) & 0x0000000F])
1177 out.write(hexdigits[(code >> 20) & 0x0000000F])
1178 out.write(hexdigits[(code >> 16) & 0x0000000F])
1179 out.write(hexdigits[(code >> 12) & 0x0000000F])
1180 out.write(hexdigits[(code >> 8) & 0x0000000F])
1181 out.write(hexdigits[(code >> 4) & 0x0000000F])
1182 out.write(hexdigits[code & 0x0000000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001183 # Map 16-bit characters to '\uxxxx'
1184 else:
1185 out.write('\\u')
Victor Stinner150016f2010-05-19 23:04:56 +00001186 out.write(hexdigits[(code >> 12) & 0x000F])
1187 out.write(hexdigits[(code >> 8) & 0x000F])
1188 out.write(hexdigits[(code >> 4) & 0x000F])
1189 out.write(hexdigits[code & 0x000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001190 else:
1191 # Copy characters as-is
1192 out.write(ch)
Victor Stinner150016f2010-05-19 23:04:56 +00001193 if self.char_width() == 2 and (ch2 is not None):
1194 out.write(ch2)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001195
1196 out.write(quote)
1197
1198
1199
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001200
1201def int_from_int(gdbval):
1202 return int(str(gdbval))
1203
1204
1205def stringify(val):
1206 # TODO: repr() puts everything on one line; pformat can be nicer, but
1207 # can lead to v.long results; this function isolates the choice
1208 if True:
1209 return repr(val)
1210 else:
1211 from pprint import pformat
1212 return pformat(val)
1213
1214
1215class PyObjectPtrPrinter:
1216 "Prints a (PyObject*)"
1217
1218 def __init__ (self, gdbval):
1219 self.gdbval = gdbval
1220
1221 def to_string (self):
1222 pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
1223 if True:
1224 return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1225 else:
1226 # Generate full proxy value then stringify it.
1227 # Doing so could be expensive
1228 proxyval = pyop.proxyval(set())
1229 return stringify(proxyval)
1230
1231def pretty_printer_lookup(gdbval):
1232 type = gdbval.type.unqualified()
1233 if type.code == gdb.TYPE_CODE_PTR:
1234 type = type.target().unqualified()
1235 t = str(type)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001236 if t in ("PyObject", "PyFrameObject", "PyUnicodeObject"):
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001237 return PyObjectPtrPrinter(gdbval)
1238
1239"""
1240During development, I've been manually invoking the code in this way:
1241(gdb) python
1242
1243import sys
1244sys.path.append('/home/david/coding/python-gdb')
1245import libpython
1246end
1247
1248then reloading it after each edit like this:
1249(gdb) python reload(libpython)
1250
1251The following code should ensure that the prettyprinter is registered
1252if the code is autoloaded by gdb when visiting libpython.so, provided
1253that this python file is installed to the same path as the library (or its
1254.debug file) plus a "-gdb.py" suffix, e.g:
1255 /usr/lib/libpython2.6.so.1.0-gdb.py
1256 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
1257"""
1258def register (obj):
1259 if obj == None:
1260 obj = gdb
1261
1262 # Wire up the pretty-printer
1263 obj.pretty_printers.append(pretty_printer_lookup)
1264
1265register (gdb.current_objfile ())
1266
1267
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001268
1269# Unfortunately, the exact API exposed by the gdb module varies somewhat
1270# from build to build
1271# See http://bugs.python.org/issue8279?#msg102276
1272
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001273class Frame(object):
1274 '''
1275 Wrapper for gdb.Frame, adding various methods
1276 '''
1277 def __init__(self, gdbframe):
1278 self._gdbframe = gdbframe
1279
1280 def older(self):
1281 older = self._gdbframe.older()
1282 if older:
1283 return Frame(older)
1284 else:
1285 return None
1286
1287 def newer(self):
1288 newer = self._gdbframe.newer()
1289 if newer:
1290 return Frame(newer)
1291 else:
1292 return None
1293
1294 def select(self):
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001295 '''If supported, select this frame and return True; return False if unsupported
1296
1297 Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
1298 onwards, but absent on Ubuntu buildbot'''
1299 if not hasattr(self._gdbframe, 'select'):
1300 print ('Unable to select frame: '
1301 'this build of gdb does not expose a gdb.Frame.select method')
1302 return False
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001303 self._gdbframe.select()
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001304 return True
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001305
1306 def get_index(self):
1307 '''Calculate index of frame, starting at 0 for the newest frame within
1308 this thread'''
1309 index = 0
1310 # Go down until you reach the newest frame:
1311 iter_frame = self
1312 while iter_frame.newer():
1313 index += 1
1314 iter_frame = iter_frame.newer()
1315 return index
1316
1317 def is_evalframeex(self):
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001318 '''Is this a PyEval_EvalFrameEx frame?'''
Victor Stinner50eb60e2010-04-20 22:32:07 +00001319 if self._gdbframe.name() == 'PyEval_EvalFrameEx':
1320 '''
1321 I believe we also need to filter on the inline
1322 struct frame_id.inline_depth, only regarding frames with
1323 an inline depth of 0 as actually being this function
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001324
Victor Stinner50eb60e2010-04-20 22:32:07 +00001325 So we reject those with type gdb.INLINE_FRAME
1326 '''
1327 if self._gdbframe.type() == gdb.NORMAL_FRAME:
1328 # We have a PyEval_EvalFrameEx frame:
1329 return True
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001330
1331 return False
1332
1333 def get_pyop(self):
1334 try:
1335 f = self._gdbframe.read_var('f')
1336 return PyFrameObjectPtr.from_pyobject_ptr(f)
1337 except ValueError:
1338 return None
1339
1340 @classmethod
1341 def get_selected_frame(cls):
1342 _gdbframe = gdb.selected_frame()
1343 if _gdbframe:
1344 return Frame(_gdbframe)
1345 return None
1346
1347 @classmethod
1348 def get_selected_python_frame(cls):
1349 '''Try to obtain the Frame for the python code in the selected frame,
1350 or None'''
1351 frame = cls.get_selected_frame()
1352
1353 while frame:
1354 if frame.is_evalframeex():
1355 return frame
1356 frame = frame.older()
1357
1358 # Not found:
1359 return None
1360
1361 def print_summary(self):
1362 if self.is_evalframeex():
1363 pyop = self.get_pyop()
1364 if pyop:
1365 sys.stdout.write('#%i %s\n' % (self.get_index(), pyop.get_truncated_repr(MAX_OUTPUT_LEN)))
1366 sys.stdout.write(pyop.current_line())
1367 else:
1368 sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1369 else:
1370 sys.stdout.write('#%i\n' % self.get_index())
1371
1372class PyList(gdb.Command):
1373 '''List the current Python source code, if any
1374
1375 Use
1376 py-list START
1377 to list at a different line number within the python source.
1378
1379 Use
1380 py-list START, END
1381 to list a specific range of lines within the python source.
1382 '''
1383
1384 def __init__(self):
1385 gdb.Command.__init__ (self,
1386 "py-list",
1387 gdb.COMMAND_FILES,
1388 gdb.COMPLETE_NONE)
1389
1390
1391 def invoke(self, args, from_tty):
1392 import re
1393
1394 start = None
1395 end = None
1396
1397 m = re.match(r'\s*(\d+)\s*', args)
1398 if m:
1399 start = int(m.group(0))
1400 end = start + 10
1401
1402 m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
1403 if m:
1404 start, end = map(int, m.groups())
1405
1406 frame = Frame.get_selected_python_frame()
1407 if not frame:
1408 print 'Unable to locate python frame'
1409 return
1410
1411 pyop = frame.get_pyop()
1412 if not pyop:
1413 print 'Unable to read information on python frame'
1414 return
1415
1416 filename = pyop.filename()
1417 lineno = pyop.current_line_num()
1418
1419 if start is None:
1420 start = lineno - 5
1421 end = lineno + 5
1422
1423 if start<1:
1424 start = 1
1425
1426 with open(filename, 'r') as f:
1427 all_lines = f.readlines()
1428 # start and end are 1-based, all_lines is 0-based;
1429 # so [start-1:end] as a python slice gives us [start, end] as a
1430 # closed interval
1431 for i, line in enumerate(all_lines[start-1:end]):
1432 linestr = str(i+start)
1433 # Highlight current line:
1434 if i + start == lineno:
1435 linestr = '>' + linestr
1436 sys.stdout.write('%4s %s' % (linestr, line))
1437
1438
1439# ...and register the command:
1440PyList()
1441
1442def move_in_stack(move_up):
1443 '''Move up or down the stack (for the py-up/py-down command)'''
1444 frame = Frame.get_selected_python_frame()
1445 while frame:
1446 if move_up:
1447 iter_frame = frame.older()
1448 else:
1449 iter_frame = frame.newer()
1450
1451 if not iter_frame:
1452 break
1453
1454 if iter_frame.is_evalframeex():
1455 # Result:
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001456 if iter_frame.select():
1457 iter_frame.print_summary()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001458 return
1459
1460 frame = iter_frame
1461
1462 if move_up:
1463 print 'Unable to find an older python frame'
1464 else:
1465 print 'Unable to find a newer python frame'
1466
1467class PyUp(gdb.Command):
1468 'Select and print the python stack frame that called this one (if any)'
1469 def __init__(self):
1470 gdb.Command.__init__ (self,
1471 "py-up",
1472 gdb.COMMAND_STACK,
1473 gdb.COMPLETE_NONE)
1474
1475
1476 def invoke(self, args, from_tty):
1477 move_in_stack(move_up=True)
1478
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001479class PyDown(gdb.Command):
1480 'Select and print the python stack frame called by this one (if any)'
1481 def __init__(self):
1482 gdb.Command.__init__ (self,
1483 "py-down",
1484 gdb.COMMAND_STACK,
1485 gdb.COMPLETE_NONE)
1486
1487
1488 def invoke(self, args, from_tty):
1489 move_in_stack(move_up=False)
1490
Victor Stinner50eb60e2010-04-20 22:32:07 +00001491# Not all builds of gdb have gdb.Frame.select
1492if hasattr(gdb.Frame, 'select'):
1493 PyUp()
1494 PyDown()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001495
1496class PyBacktrace(gdb.Command):
1497 'Display the current python frame and all the frames within its call stack (if any)'
1498 def __init__(self):
1499 gdb.Command.__init__ (self,
1500 "py-bt",
1501 gdb.COMMAND_STACK,
1502 gdb.COMPLETE_NONE)
1503
1504
1505 def invoke(self, args, from_tty):
1506 frame = Frame.get_selected_python_frame()
1507 while frame:
1508 if frame.is_evalframeex():
1509 frame.print_summary()
1510 frame = frame.older()
1511
1512PyBacktrace()
1513
1514class PyPrint(gdb.Command):
1515 'Look up the given python variable name, and print it'
1516 def __init__(self):
1517 gdb.Command.__init__ (self,
1518 "py-print",
1519 gdb.COMMAND_DATA,
1520 gdb.COMPLETE_NONE)
1521
1522
1523 def invoke(self, args, from_tty):
1524 name = str(args)
1525
1526 frame = Frame.get_selected_python_frame()
1527 if not frame:
1528 print 'Unable to locate python frame'
1529 return
1530
1531 pyop_frame = frame.get_pyop()
1532 if not pyop_frame:
1533 print 'Unable to read information on python frame'
1534 return
1535
1536 pyop_var, scope = pyop_frame.get_var_by_name(name)
1537
1538 if pyop_var:
1539 print ('%s %r = %s'
1540 % (scope,
1541 name,
1542 pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
1543 else:
1544 print '%r not found' % name
1545
1546PyPrint()
1547
1548class PyLocals(gdb.Command):
1549 'Look up the given python variable name, and print it'
1550 def __init__(self):
1551 gdb.Command.__init__ (self,
1552 "py-locals",
1553 gdb.COMMAND_DATA,
1554 gdb.COMPLETE_NONE)
1555
1556
1557 def invoke(self, args, from_tty):
1558 name = str(args)
1559
1560 frame = Frame.get_selected_python_frame()
1561 if not frame:
1562 print 'Unable to locate python frame'
1563 return
1564
1565 pyop_frame = frame.get_pyop()
1566 if not pyop_frame:
1567 print 'Unable to read information on python frame'
1568 return
1569
1570 for pyop_name, pyop_value in pyop_frame.iter_locals():
1571 print ('%s = %s'
1572 % (pyop_name.proxyval(set()),
1573 pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
1574
1575PyLocals()