blob: ac4aff5e32a3b844df76316eecf3b4d74692ef64 [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
Georg Brandlb639c142010-07-14 08:54:40 +000046import sys
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000047
48# Look up the gdb.Type for some standard types:
49_type_char_ptr = gdb.lookup_type('char').pointer() # char*
50_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
51_type_void_ptr = gdb.lookup_type('void').pointer() # void*
52_type_size_t = gdb.lookup_type('size_t')
53
54SIZEOF_VOID_P = _type_void_ptr.sizeof
55
56
57Py_TPFLAGS_HEAPTYPE = (1L << 9)
58
Benjamin Peterson6a6666a2010-04-11 21:49:28 +000059Py_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
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000315 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
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000321 if tp_flags & Py_TPFLAGS_BYTES_SUBCLASS:
Victor Stinner67df3a42010-04-21 13:53:05 +0000322 return PyBytesObjectPtr
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000323 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
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000358class PyVarObjectPtr(PyObjectPtr):
359 _typename = 'PyVarObject'
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000360
361class ProxyAlreadyVisited(object):
362 '''
363 Placeholder proxy to use when protecting against infinite recursion due to
364 loops in the object graph.
365
366 Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
367 '''
368 def __init__(self, rep):
369 self._rep = rep
370
371 def __repr__(self):
372 return self._rep
373
374
375def _write_instance_repr(out, visited, name, pyop_attrdict, address):
376 '''Shared code for use by old-style and new-style classes:
377 write a representation to file-like object "out"'''
378 out.write('<')
379 out.write(name)
380
381 # Write dictionary of instance attributes:
382 if isinstance(pyop_attrdict, PyDictObjectPtr):
383 out.write('(')
384 first = True
385 for pyop_arg, pyop_val in pyop_attrdict.iteritems():
386 if not first:
387 out.write(', ')
388 first = False
389 out.write(pyop_arg.proxyval(visited))
390 out.write('=')
391 pyop_val.write_repr(out, visited)
392 out.write(')')
393 out.write(' at remote 0x%x>' % address)
394
395
396class InstanceProxy(object):
397
398 def __init__(self, cl_name, attrdict, address):
399 self.cl_name = cl_name
400 self.attrdict = attrdict
401 self.address = address
402
403 def __repr__(self):
404 if isinstance(self.attrdict, dict):
405 kwargs = ', '.join(["%s=%r" % (arg, val)
406 for arg, val in self.attrdict.iteritems()])
407 return '<%s(%s) at remote 0x%x>' % (self.cl_name,
408 kwargs, self.address)
409 else:
410 return '<%s at remote 0x%x>' % (self.cl_name,
411 self.address)
412
413def _PyObject_VAR_SIZE(typeobj, nitems):
414 return ( ( typeobj.field('tp_basicsize') +
415 nitems * typeobj.field('tp_itemsize') +
416 (SIZEOF_VOID_P - 1)
417 ) & ~(SIZEOF_VOID_P - 1)
418 ).cast(_type_size_t)
419
420class HeapTypeObjectPtr(PyObjectPtr):
421 _typename = 'PyObject'
422
423 def get_attr_dict(self):
424 '''
425 Get the PyDictObject ptr representing the attribute dictionary
426 (or None if there's a problem)
427 '''
428 try:
429 typeobj = self.type()
430 dictoffset = int_from_int(typeobj.field('tp_dictoffset'))
431 if dictoffset != 0:
432 if dictoffset < 0:
433 type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer()
434 tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size'])
435 if tsize < 0:
436 tsize = -tsize
437 size = _PyObject_VAR_SIZE(typeobj, tsize)
438 dictoffset += size
439 assert dictoffset > 0
440 assert dictoffset % SIZEOF_VOID_P == 0
441
442 dictptr = self._gdbval.cast(_type_char_ptr) + dictoffset
443 PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
444 dictptr = dictptr.cast(PyObjectPtrPtr)
445 return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
446 except RuntimeError:
447 # Corrupt data somewhere; fail safe
448 pass
449
450 # Not found, or some kind of error:
451 return None
452
453 def proxyval(self, visited):
454 '''
455 Support for new-style classes.
456
457 Currently we just locate the dictionary using a transliteration to
458 python of _PyObject_GetDictPtr, ignoring descriptors
459 '''
460 # Guard against infinite loops:
461 if self.as_address() in visited:
462 return ProxyAlreadyVisited('<...>')
463 visited.add(self.as_address())
464
465 pyop_attr_dict = self.get_attr_dict()
466 if pyop_attr_dict:
467 attr_dict = pyop_attr_dict.proxyval(visited)
468 else:
469 attr_dict = {}
470 tp_name = self.safe_tp_name()
471
472 # New-style class:
473 return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
474
475 def write_repr(self, out, visited):
476 # Guard against infinite loops:
477 if self.as_address() in visited:
478 out.write('<...>')
479 return
480 visited.add(self.as_address())
481
482 pyop_attrdict = self.get_attr_dict()
483 _write_instance_repr(out, visited,
484 self.safe_tp_name(), pyop_attrdict, self.as_address())
485
486class ProxyException(Exception):
487 def __init__(self, tp_name, args):
488 self.tp_name = tp_name
489 self.args = args
490
491 def __repr__(self):
492 return '%s%r' % (self.tp_name, self.args)
493
494class PyBaseExceptionObjectPtr(PyObjectPtr):
495 """
496 Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
497 within the process being debugged.
498 """
499 _typename = 'PyBaseExceptionObject'
500
501 def proxyval(self, visited):
502 # Guard against infinite loops:
503 if self.as_address() in visited:
504 return ProxyAlreadyVisited('(...)')
505 visited.add(self.as_address())
506 arg_proxy = self.pyop_field('args').proxyval(visited)
507 return ProxyException(self.safe_tp_name(),
508 arg_proxy)
509
510 def write_repr(self, out, visited):
511 # Guard against infinite loops:
512 if self.as_address() in visited:
513 out.write('(...)')
514 return
515 visited.add(self.as_address())
516
517 out.write(self.safe_tp_name())
518 self.write_field_repr('args', out, visited)
519
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000520class PyClassObjectPtr(PyObjectPtr):
521 """
522 Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
523 instance within the process being debugged.
524 """
525 _typename = 'PyClassObject'
526
527
528class BuiltInFunctionProxy(object):
529 def __init__(self, ml_name):
530 self.ml_name = ml_name
531
532 def __repr__(self):
533 return "<built-in function %s>" % self.ml_name
534
535class BuiltInMethodProxy(object):
536 def __init__(self, ml_name, pyop_m_self):
537 self.ml_name = ml_name
538 self.pyop_m_self = pyop_m_self
539
540 def __repr__(self):
541 return ('<built-in method %s of %s object at remote 0x%x>'
542 % (self.ml_name,
543 self.pyop_m_self.safe_tp_name(),
544 self.pyop_m_self.as_address())
545 )
546
547class PyCFunctionObjectPtr(PyObjectPtr):
548 """
549 Class wrapping a gdb.Value that's a PyCFunctionObject*
550 (see Include/methodobject.h and Objects/methodobject.c)
551 """
552 _typename = 'PyCFunctionObject'
553
554 def proxyval(self, visited):
555 m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
556 ml_name = m_ml['ml_name'].string()
557
558 pyop_m_self = self.pyop_field('m_self')
559 if pyop_m_self.is_null():
560 return BuiltInFunctionProxy(ml_name)
561 else:
562 return BuiltInMethodProxy(ml_name, pyop_m_self)
563
564
565class PyCodeObjectPtr(PyObjectPtr):
566 """
567 Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance
568 within the process being debugged.
569 """
570 _typename = 'PyCodeObject'
571
572 def addr2line(self, addrq):
573 '''
574 Get the line number for a given bytecode offset
575
576 Analogous to PyCode_Addr2Line; translated from pseudocode in
577 Objects/lnotab_notes.txt
578 '''
579 co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
580
581 # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
582 # not 0, as lnotab_notes.txt has it:
583 lineno = int_from_int(self.field('co_firstlineno'))
584
585 addr = 0
586 for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
587 addr += ord(addr_incr)
588 if addr > addrq:
589 return lineno
590 lineno += ord(line_incr)
591 return lineno
592
593
594class PyDictObjectPtr(PyObjectPtr):
595 """
596 Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
597 within the process being debugged.
598 """
599 _typename = 'PyDictObject'
600
601 def iteritems(self):
602 '''
603 Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
604 analagous to dict.iteritems()
605 '''
606 for i in safe_range(self.field('ma_mask') + 1):
607 ep = self.field('ma_table') + i
608 pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
609 if not pyop_value.is_null():
610 pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
611 yield (pyop_key, pyop_value)
612
613 def proxyval(self, visited):
614 # Guard against infinite loops:
615 if self.as_address() in visited:
616 return ProxyAlreadyVisited('{...}')
617 visited.add(self.as_address())
618
619 result = {}
620 for pyop_key, pyop_value in self.iteritems():
621 proxy_key = pyop_key.proxyval(visited)
622 proxy_value = pyop_value.proxyval(visited)
623 result[proxy_key] = proxy_value
624 return result
625
626 def write_repr(self, out, visited):
627 # Guard against infinite loops:
628 if self.as_address() in visited:
629 out.write('{...}')
630 return
631 visited.add(self.as_address())
632
633 out.write('{')
634 first = True
635 for pyop_key, pyop_value in self.iteritems():
636 if not first:
637 out.write(', ')
638 first = False
639 pyop_key.write_repr(out, visited)
640 out.write(': ')
641 pyop_value.write_repr(out, visited)
642 out.write('}')
643
644class PyInstanceObjectPtr(PyObjectPtr):
645 _typename = 'PyInstanceObject'
646
647 def proxyval(self, visited):
648 # Guard against infinite loops:
649 if self.as_address() in visited:
650 return ProxyAlreadyVisited('<...>')
651 visited.add(self.as_address())
652
653 # Get name of class:
654 in_class = self.pyop_field('in_class')
655 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
656
657 # Get dictionary of instance attributes:
658 in_dict = self.pyop_field('in_dict').proxyval(visited)
659
660 # Old-style class:
661 return InstanceProxy(cl_name, in_dict, long(self._gdbval))
662
663 def write_repr(self, out, visited):
664 # Guard against infinite loops:
665 if self.as_address() in visited:
666 out.write('<...>')
667 return
668 visited.add(self.as_address())
669
670 # Old-style class:
671
672 # Get name of class:
673 in_class = self.pyop_field('in_class')
674 cl_name = in_class.pyop_field('cl_name').proxyval(visited)
675
676 # Get dictionary of instance attributes:
677 pyop_in_dict = self.pyop_field('in_dict')
678
679 _write_instance_repr(out, visited,
680 cl_name, pyop_in_dict, self.as_address())
681
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000682class PyListObjectPtr(PyObjectPtr):
683 _typename = 'PyListObject'
684
685 def __getitem__(self, i):
686 # Get the gdb.Value for the (PyObject*) with the given index:
687 field_ob_item = self.field('ob_item')
688 return field_ob_item[i]
689
690 def proxyval(self, visited):
691 # Guard against infinite loops:
692 if self.as_address() in visited:
693 return ProxyAlreadyVisited('[...]')
694 visited.add(self.as_address())
695
696 result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
697 for i in safe_range(int_from_int(self.field('ob_size')))]
698 return result
699
700 def write_repr(self, out, visited):
701 # Guard against infinite loops:
702 if self.as_address() in visited:
703 out.write('[...]')
704 return
705 visited.add(self.as_address())
706
707 out.write('[')
708 for i in safe_range(int_from_int(self.field('ob_size'))):
709 if i > 0:
710 out.write(', ')
711 element = PyObjectPtr.from_pyobject_ptr(self[i])
712 element.write_repr(out, visited)
713 out.write(']')
714
715class PyLongObjectPtr(PyObjectPtr):
716 _typename = 'PyLongObject'
717
718 def proxyval(self, visited):
719 '''
720 Python's Include/longobjrep.h has this declaration:
721 struct _longobject {
722 PyObject_VAR_HEAD
723 digit ob_digit[1];
724 };
725
726 with this description:
727 The absolute value of a number is equal to
728 SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
729 Negative numbers are represented with ob_size < 0;
730 zero is represented by ob_size == 0.
731
732 where SHIFT can be either:
733 #define PyLong_SHIFT 30
734 #define PyLong_SHIFT 15
735 '''
736 ob_size = long(self.field('ob_size'))
737 if ob_size == 0:
738 return 0L
739
740 ob_digit = self.field('ob_digit')
741
742 if gdb.lookup_type('digit').sizeof == 2:
743 SHIFT = 15L
744 else:
745 SHIFT = 30L
746
747 digits = [long(ob_digit[i]) * 2**(SHIFT*i)
748 for i in safe_range(abs(ob_size))]
749 result = sum(digits)
750 if ob_size < 0:
751 result = -result
752 return result
753
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000754 def write_repr(self, out, visited):
755 # Write this out as a Python 3 int literal, i.e. without the "L" suffix
756 proxy = self.proxyval(visited)
757 out.write("%s" % proxy)
758
759
760class PyBoolObjectPtr(PyLongObjectPtr):
761 """
762 Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
763 <bool> instances (Py_True/Py_False) within the process being debugged.
764 """
765 def proxyval(self, visited):
766 if PyLongObjectPtr.proxyval(self, visited):
767 return True
768 else:
769 return False
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000770
771class PyNoneStructPtr(PyObjectPtr):
772 """
773 Class wrapping a gdb.Value that's a PyObject* pointing to the
774 singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
775 """
776 _typename = 'PyObject'
777
778 def proxyval(self, visited):
779 return None
780
781
782class PyFrameObjectPtr(PyObjectPtr):
783 _typename = 'PyFrameObject'
784
785 def __init__(self, gdbval, cast_to):
786 PyObjectPtr.__init__(self, gdbval, cast_to)
787
788 if not self.is_optimized_out():
789 self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
790 self.co_name = self.co.pyop_field('co_name')
791 self.co_filename = self.co.pyop_field('co_filename')
792
793 self.f_lineno = int_from_int(self.field('f_lineno'))
794 self.f_lasti = int_from_int(self.field('f_lasti'))
795 self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
796 self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
797
798 def iter_locals(self):
799 '''
800 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
801 the local variables of this frame
802 '''
803 if self.is_optimized_out():
804 return
805
806 f_localsplus = self.field('f_localsplus')
807 for i in safe_range(self.co_nlocals):
808 pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
809 if not pyop_value.is_null():
810 pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
811 yield (pyop_name, pyop_value)
812
813 def iter_globals(self):
814 '''
815 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
816 the global variables of this frame
817 '''
818 if self.is_optimized_out():
819 return
820
821 pyop_globals = self.pyop_field('f_globals')
822 return pyop_globals.iteritems()
823
824 def iter_builtins(self):
825 '''
826 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
827 the builtin variables
828 '''
829 if self.is_optimized_out():
830 return
831
832 pyop_builtins = self.pyop_field('f_builtins')
833 return pyop_builtins.iteritems()
834
835 def get_var_by_name(self, name):
836 '''
837 Look for the named local variable, returning a (PyObjectPtr, scope) pair
838 where scope is a string 'local', 'global', 'builtin'
839
840 If not found, return (None, None)
841 '''
842 for pyop_name, pyop_value in self.iter_locals():
843 if name == pyop_name.proxyval(set()):
844 return pyop_value, 'local'
845 for pyop_name, pyop_value in self.iter_globals():
846 if name == pyop_name.proxyval(set()):
847 return pyop_value, 'global'
848 for pyop_name, pyop_value in self.iter_builtins():
849 if name == pyop_name.proxyval(set()):
850 return pyop_value, 'builtin'
851 return None, None
852
853 def filename(self):
854 '''Get the path of the current Python source file, as a string'''
855 if self.is_optimized_out():
856 return '(frame information optimized out)'
857 return self.co_filename.proxyval(set())
858
859 def current_line_num(self):
860 '''Get current line number as an integer (1-based)
861
862 Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
863
864 See Objects/lnotab_notes.txt
865 '''
866 if self.is_optimized_out():
867 return None
868 f_trace = self.field('f_trace')
869 if long(f_trace) != 0:
870 # we have a non-NULL f_trace:
871 return self.f_lineno
872 else:
873 #try:
874 return self.co.addr2line(self.f_lasti)
875 #except ValueError:
876 # return self.f_lineno
877
878 def current_line(self):
879 '''Get the text of the current source line as a string, with a trailing
880 newline character'''
881 if self.is_optimized_out():
882 return '(frame information optimized out)'
883 with open(self.filename(), 'r') as f:
884 all_lines = f.readlines()
885 # Convert from 1-based current_line_num to 0-based list offset:
886 return all_lines[self.current_line_num()-1]
887
888 def write_repr(self, out, visited):
889 if self.is_optimized_out():
890 out.write('(frame information optimized out)')
891 return
892 out.write('Frame 0x%x, for file %s, line %i, in %s ('
893 % (self.as_address(),
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000894 self.co_filename.proxyval(visited),
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000895 self.current_line_num(),
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000896 self.co_name.proxyval(visited)))
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000897 first = True
898 for pyop_name, pyop_value in self.iter_locals():
899 if not first:
900 out.write(', ')
901 first = False
902
903 out.write(pyop_name.proxyval(visited))
904 out.write('=')
905 pyop_value.write_repr(out, visited)
906
907 out.write(')')
908
909class PySetObjectPtr(PyObjectPtr):
910 _typename = 'PySetObject'
911
912 def proxyval(self, visited):
913 # Guard against infinite loops:
914 if self.as_address() in visited:
915 return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
916 visited.add(self.as_address())
917
918 members = []
919 table = self.field('table')
920 for i in safe_range(self.field('mask')+1):
921 setentry = table[i]
922 key = setentry['key']
923 if key != 0:
924 key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
925 if key_proxy != '<dummy key>':
926 members.append(key_proxy)
927 if self.safe_tp_name() == 'frozenset':
928 return frozenset(members)
929 else:
930 return set(members)
931
932 def write_repr(self, out, visited):
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000933 # Emulate Python 3's set_repr
934 tp_name = self.safe_tp_name()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000935
936 # Guard against infinite loops:
937 if self.as_address() in visited:
938 out.write('(...)')
939 return
940 visited.add(self.as_address())
941
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000942 # Python 3's set_repr special-cases the empty set:
943 if not self.field('used'):
944 out.write(tp_name)
945 out.write('()')
946 return
947
948 # Python 3 uses {} for set literals:
949 if tp_name != 'set':
950 out.write(tp_name)
951 out.write('(')
952
953 out.write('{')
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000954 first = True
955 table = self.field('table')
956 for i in safe_range(self.field('mask')+1):
957 setentry = table[i]
958 key = setentry['key']
959 if key != 0:
960 pyop_key = PyObjectPtr.from_pyobject_ptr(key)
961 key_proxy = pyop_key.proxyval(visited) # FIXME!
962 if key_proxy != '<dummy key>':
963 if not first:
964 out.write(', ')
965 first = False
966 pyop_key.write_repr(out, visited)
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000967 out.write('}')
968
969 if tp_name != 'set':
970 out.write(')')
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000971
972
Victor Stinner67df3a42010-04-21 13:53:05 +0000973class PyBytesObjectPtr(PyObjectPtr):
974 _typename = 'PyBytesObject'
Benjamin Peterson6a6666a2010-04-11 21:49:28 +0000975
976 def __str__(self):
977 field_ob_size = self.field('ob_size')
978 field_ob_sval = self.field('ob_sval')
979 char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr)
980 return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
981
982 def proxyval(self, visited):
983 return str(self)
984
Martin v. Löwis5ae68102010-04-21 22:38:42 +0000985 def write_repr(self, out, visited):
986 # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix
987
988 # Get a PyStringObject* within the Python 2 gdb process:
989 proxy = self.proxyval(visited)
990
991 # Transliteration of Python 3's Objects/bytesobject.c:PyBytes_Repr
992 # to Python 2 code:
993 quote = "'"
994 if "'" in proxy and not '"' in proxy:
995 quote = '"'
996 out.write('b')
997 out.write(quote)
998 for byte in proxy:
999 if byte == quote or byte == '\\':
1000 out.write('\\')
1001 out.write(byte)
1002 elif byte == '\t':
1003 out.write('\\t')
1004 elif byte == '\n':
1005 out.write('\\n')
1006 elif byte == '\r':
1007 out.write('\\r')
1008 elif byte < ' ' or ord(byte) >= 0x7f:
1009 out.write('\\x')
1010 out.write(hexdigits[(ord(byte) & 0xf0) >> 4])
1011 out.write(hexdigits[ord(byte) & 0xf])
1012 else:
1013 out.write(byte)
1014 out.write(quote)
1015
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001016class PyTupleObjectPtr(PyObjectPtr):
1017 _typename = 'PyTupleObject'
1018
1019 def __getitem__(self, i):
1020 # Get the gdb.Value for the (PyObject*) with the given index:
1021 field_ob_item = self.field('ob_item')
1022 return field_ob_item[i]
1023
1024 def proxyval(self, visited):
1025 # Guard against infinite loops:
1026 if self.as_address() in visited:
1027 return ProxyAlreadyVisited('(...)')
1028 visited.add(self.as_address())
1029
1030 result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
1031 for i in safe_range(int_from_int(self.field('ob_size')))])
1032 return result
1033
1034 def write_repr(self, out, visited):
1035 # Guard against infinite loops:
1036 if self.as_address() in visited:
1037 out.write('(...)')
1038 return
1039 visited.add(self.as_address())
1040
1041 out.write('(')
1042 for i in safe_range(int_from_int(self.field('ob_size'))):
1043 if i > 0:
1044 out.write(', ')
1045 element = PyObjectPtr.from_pyobject_ptr(self[i])
1046 element.write_repr(out, visited)
1047 if self.field('ob_size') == 1:
1048 out.write(',)')
1049 else:
1050 out.write(')')
1051
1052class PyTypeObjectPtr(PyObjectPtr):
1053 _typename = 'PyTypeObject'
1054
1055
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001056def _unichr_is_printable(char):
1057 # Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
1058 if char == u" ":
1059 return True
1060 import unicodedata
1061 return unicodedata.category(char)[0] not in ("C", "Z")
1062
1063
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001064class PyUnicodeObjectPtr(PyObjectPtr):
1065 _typename = 'PyUnicodeObject'
1066
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001067 def char_width(self):
1068 _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
1069 return _type_Py_UNICODE.sizeof
1070
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001071 def proxyval(self, visited):
1072 # From unicodeobject.h:
1073 # Py_ssize_t length; /* Length of raw Unicode data in buffer */
1074 # Py_UNICODE *str; /* Raw Unicode buffer */
1075 field_length = long(self.field('length'))
1076 field_str = self.field('str')
1077
1078 # Gather a list of ints from the Py_UNICODE array; these are either
1079 # UCS-2 or UCS-4 code points:
1080 Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
1081
1082 # Convert the int code points to unicode characters, and generate a
1083 # local unicode instance:
1084 result = u''.join([unichr(ucs) for ucs in Py_UNICODEs])
1085 return result
1086
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001087 def write_repr(self, out, visited):
1088 # Write this out as a Python 3 str literal, i.e. without a "u" prefix
1089
1090 # Get a PyUnicodeObject* within the Python 2 gdb process:
1091 proxy = self.proxyval(visited)
1092
1093 # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr
1094 # to Python 2:
1095 if "'" in proxy and '"' not in proxy:
1096 quote = '"'
1097 else:
1098 quote = "'"
1099 out.write(quote)
1100
1101 i = 0
1102 while i < len(proxy):
1103 ch = proxy[i]
1104 i += 1
1105
1106 # Escape quotes and backslashes
1107 if ch == quote or ch == '\\':
1108 out.write('\\')
1109 out.write(ch)
1110
1111 # Map special whitespace to '\t', \n', '\r'
1112 elif ch == '\t':
1113 out.write('\\t')
1114 elif ch == '\n':
1115 out.write('\\n')
1116 elif ch == '\r':
1117 out.write('\\r')
1118
1119 # Map non-printable US ASCII to '\xhh' */
1120 elif ch < ' ' or ch == 0x7F:
1121 out.write('\\x')
1122 out.write(hexdigits[(ord(ch) >> 4) & 0x000F])
1123 out.write(hexdigits[ord(ch) & 0x000F])
1124
1125 # Copy ASCII characters as-is
1126 elif ord(ch) < 0x7F:
1127 out.write(ch)
1128
1129 # Non-ASCII characters
1130 else:
Victor Stinner150016f2010-05-19 23:04:56 +00001131 ucs = ch
1132 orig_ucs = None
1133 if self.char_width() == 2:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001134 # Get code point from surrogate pair
Victor Stinner150016f2010-05-19 23:04:56 +00001135 if (i < len(proxy)
1136 and 0xD800 <= ord(ch) < 0xDC00 \
1137 and 0xDC00 <= ord(proxy[i]) <= 0xDFFF):
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001138 ch2 = proxy[i]
Victor Stinner150016f2010-05-19 23:04:56 +00001139 code = (ord(ch) & 0x03FF) << 10
1140 code |= ord(ch2) & 0x03FF
1141 code += 0x00010000
1142 orig_ucs = ucs
1143 ucs = unichr(code)
1144 i += 1
1145 else:
1146 ch2 = None
1147
1148 printable = _unichr_is_printable(ucs)
1149 if printable:
1150 try:
1151 ucs.encode(ENCODING)
1152 except UnicodeEncodeError:
1153 printable = False
1154 if orig_ucs is not None:
1155 ucs = orig_ucs
1156 i -= 1
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001157
1158 # Map Unicode whitespace and control characters
1159 # (categories Z* and C* except ASCII space)
Victor Stinner150016f2010-05-19 23:04:56 +00001160 if not printable:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001161 # Unfortuately, Python 2's unicode type doesn't seem
1162 # to expose the "isprintable" method
Victor Stinner150016f2010-05-19 23:04:56 +00001163 code = ord(ucs)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001164
1165 # Map 8-bit characters to '\\xhh'
Victor Stinner150016f2010-05-19 23:04:56 +00001166 if code <= 0xff:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001167 out.write('\\x')
Victor Stinner150016f2010-05-19 23:04:56 +00001168 out.write(hexdigits[(code >> 4) & 0x000F])
1169 out.write(hexdigits[code & 0x000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001170 # Map 21-bit characters to '\U00xxxxxx'
Victor Stinner150016f2010-05-19 23:04:56 +00001171 elif code >= 0x10000:
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001172 out.write('\\U')
Victor Stinner150016f2010-05-19 23:04:56 +00001173 out.write(hexdigits[(code >> 28) & 0x0000000F])
1174 out.write(hexdigits[(code >> 24) & 0x0000000F])
1175 out.write(hexdigits[(code >> 20) & 0x0000000F])
1176 out.write(hexdigits[(code >> 16) & 0x0000000F])
1177 out.write(hexdigits[(code >> 12) & 0x0000000F])
1178 out.write(hexdigits[(code >> 8) & 0x0000000F])
1179 out.write(hexdigits[(code >> 4) & 0x0000000F])
1180 out.write(hexdigits[code & 0x0000000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001181 # Map 16-bit characters to '\uxxxx'
1182 else:
1183 out.write('\\u')
Victor Stinner150016f2010-05-19 23:04:56 +00001184 out.write(hexdigits[(code >> 12) & 0x000F])
1185 out.write(hexdigits[(code >> 8) & 0x000F])
1186 out.write(hexdigits[(code >> 4) & 0x000F])
1187 out.write(hexdigits[code & 0x000F])
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001188 else:
1189 # Copy characters as-is
1190 out.write(ch)
Victor Stinner150016f2010-05-19 23:04:56 +00001191 if self.char_width() == 2 and (ch2 is not None):
1192 out.write(ch2)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001193
1194 out.write(quote)
1195
1196
1197
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001198
1199def int_from_int(gdbval):
1200 return int(str(gdbval))
1201
1202
1203def stringify(val):
1204 # TODO: repr() puts everything on one line; pformat can be nicer, but
1205 # can lead to v.long results; this function isolates the choice
1206 if True:
1207 return repr(val)
1208 else:
1209 from pprint import pformat
1210 return pformat(val)
1211
1212
1213class PyObjectPtrPrinter:
1214 "Prints a (PyObject*)"
1215
1216 def __init__ (self, gdbval):
1217 self.gdbval = gdbval
1218
1219 def to_string (self):
1220 pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
1221 if True:
1222 return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1223 else:
1224 # Generate full proxy value then stringify it.
1225 # Doing so could be expensive
1226 proxyval = pyop.proxyval(set())
1227 return stringify(proxyval)
1228
1229def pretty_printer_lookup(gdbval):
1230 type = gdbval.type.unqualified()
1231 if type.code == gdb.TYPE_CODE_PTR:
1232 type = type.target().unqualified()
1233 t = str(type)
Martin v. Löwis5ae68102010-04-21 22:38:42 +00001234 if t in ("PyObject", "PyFrameObject", "PyUnicodeObject"):
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001235 return PyObjectPtrPrinter(gdbval)
1236
1237"""
1238During development, I've been manually invoking the code in this way:
1239(gdb) python
1240
1241import sys
1242sys.path.append('/home/david/coding/python-gdb')
1243import libpython
1244end
1245
1246then reloading it after each edit like this:
1247(gdb) python reload(libpython)
1248
1249The following code should ensure that the prettyprinter is registered
1250if the code is autoloaded by gdb when visiting libpython.so, provided
1251that this python file is installed to the same path as the library (or its
1252.debug file) plus a "-gdb.py" suffix, e.g:
1253 /usr/lib/libpython2.6.so.1.0-gdb.py
1254 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
1255"""
1256def register (obj):
1257 if obj == None:
1258 obj = gdb
1259
1260 # Wire up the pretty-printer
1261 obj.pretty_printers.append(pretty_printer_lookup)
1262
1263register (gdb.current_objfile ())
1264
1265
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001266
1267# Unfortunately, the exact API exposed by the gdb module varies somewhat
1268# from build to build
1269# See http://bugs.python.org/issue8279?#msg102276
1270
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001271class Frame(object):
1272 '''
1273 Wrapper for gdb.Frame, adding various methods
1274 '''
1275 def __init__(self, gdbframe):
1276 self._gdbframe = gdbframe
1277
1278 def older(self):
1279 older = self._gdbframe.older()
1280 if older:
1281 return Frame(older)
1282 else:
1283 return None
1284
1285 def newer(self):
1286 newer = self._gdbframe.newer()
1287 if newer:
1288 return Frame(newer)
1289 else:
1290 return None
1291
1292 def select(self):
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001293 '''If supported, select this frame and return True; return False if unsupported
1294
1295 Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
1296 onwards, but absent on Ubuntu buildbot'''
1297 if not hasattr(self._gdbframe, 'select'):
1298 print ('Unable to select frame: '
1299 'this build of gdb does not expose a gdb.Frame.select method')
1300 return False
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001301 self._gdbframe.select()
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001302 return True
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001303
1304 def get_index(self):
1305 '''Calculate index of frame, starting at 0 for the newest frame within
1306 this thread'''
1307 index = 0
1308 # Go down until you reach the newest frame:
1309 iter_frame = self
1310 while iter_frame.newer():
1311 index += 1
1312 iter_frame = iter_frame.newer()
1313 return index
1314
1315 def is_evalframeex(self):
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001316 '''Is this a PyEval_EvalFrameEx frame?'''
Victor Stinner50eb60e2010-04-20 22:32:07 +00001317 if self._gdbframe.name() == 'PyEval_EvalFrameEx':
1318 '''
1319 I believe we also need to filter on the inline
1320 struct frame_id.inline_depth, only regarding frames with
1321 an inline depth of 0 as actually being this function
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001322
Victor Stinner50eb60e2010-04-20 22:32:07 +00001323 So we reject those with type gdb.INLINE_FRAME
1324 '''
1325 if self._gdbframe.type() == gdb.NORMAL_FRAME:
1326 # We have a PyEval_EvalFrameEx frame:
1327 return True
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001328
1329 return False
1330
1331 def get_pyop(self):
1332 try:
1333 f = self._gdbframe.read_var('f')
1334 return PyFrameObjectPtr.from_pyobject_ptr(f)
1335 except ValueError:
1336 return None
1337
1338 @classmethod
1339 def get_selected_frame(cls):
1340 _gdbframe = gdb.selected_frame()
1341 if _gdbframe:
1342 return Frame(_gdbframe)
1343 return None
1344
1345 @classmethod
1346 def get_selected_python_frame(cls):
1347 '''Try to obtain the Frame for the python code in the selected frame,
1348 or None'''
1349 frame = cls.get_selected_frame()
1350
1351 while frame:
1352 if frame.is_evalframeex():
1353 return frame
1354 frame = frame.older()
1355
1356 # Not found:
1357 return None
1358
1359 def print_summary(self):
1360 if self.is_evalframeex():
1361 pyop = self.get_pyop()
1362 if pyop:
1363 sys.stdout.write('#%i %s\n' % (self.get_index(), pyop.get_truncated_repr(MAX_OUTPUT_LEN)))
1364 sys.stdout.write(pyop.current_line())
1365 else:
1366 sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1367 else:
1368 sys.stdout.write('#%i\n' % self.get_index())
1369
1370class PyList(gdb.Command):
1371 '''List the current Python source code, if any
1372
1373 Use
1374 py-list START
1375 to list at a different line number within the python source.
1376
1377 Use
1378 py-list START, END
1379 to list a specific range of lines within the python source.
1380 '''
1381
1382 def __init__(self):
1383 gdb.Command.__init__ (self,
1384 "py-list",
1385 gdb.COMMAND_FILES,
1386 gdb.COMPLETE_NONE)
1387
1388
1389 def invoke(self, args, from_tty):
1390 import re
1391
1392 start = None
1393 end = None
1394
1395 m = re.match(r'\s*(\d+)\s*', args)
1396 if m:
1397 start = int(m.group(0))
1398 end = start + 10
1399
1400 m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
1401 if m:
1402 start, end = map(int, m.groups())
1403
1404 frame = Frame.get_selected_python_frame()
1405 if not frame:
1406 print 'Unable to locate python frame'
1407 return
1408
1409 pyop = frame.get_pyop()
1410 if not pyop:
1411 print 'Unable to read information on python frame'
1412 return
1413
1414 filename = pyop.filename()
1415 lineno = pyop.current_line_num()
1416
1417 if start is None:
1418 start = lineno - 5
1419 end = lineno + 5
1420
1421 if start<1:
1422 start = 1
1423
1424 with open(filename, 'r') as f:
1425 all_lines = f.readlines()
1426 # start and end are 1-based, all_lines is 0-based;
1427 # so [start-1:end] as a python slice gives us [start, end] as a
1428 # closed interval
1429 for i, line in enumerate(all_lines[start-1:end]):
1430 linestr = str(i+start)
1431 # Highlight current line:
1432 if i + start == lineno:
1433 linestr = '>' + linestr
1434 sys.stdout.write('%4s %s' % (linestr, line))
1435
1436
1437# ...and register the command:
1438PyList()
1439
1440def move_in_stack(move_up):
1441 '''Move up or down the stack (for the py-up/py-down command)'''
1442 frame = Frame.get_selected_python_frame()
1443 while frame:
1444 if move_up:
1445 iter_frame = frame.older()
1446 else:
1447 iter_frame = frame.newer()
1448
1449 if not iter_frame:
1450 break
1451
1452 if iter_frame.is_evalframeex():
1453 # Result:
Martin v. Löwis5226fd62010-04-21 06:05:58 +00001454 if iter_frame.select():
1455 iter_frame.print_summary()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001456 return
1457
1458 frame = iter_frame
1459
1460 if move_up:
1461 print 'Unable to find an older python frame'
1462 else:
1463 print 'Unable to find a newer python frame'
1464
1465class PyUp(gdb.Command):
1466 'Select and print the python stack frame that called this one (if any)'
1467 def __init__(self):
1468 gdb.Command.__init__ (self,
1469 "py-up",
1470 gdb.COMMAND_STACK,
1471 gdb.COMPLETE_NONE)
1472
1473
1474 def invoke(self, args, from_tty):
1475 move_in_stack(move_up=True)
1476
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001477class PyDown(gdb.Command):
1478 'Select and print the python stack frame called by this one (if any)'
1479 def __init__(self):
1480 gdb.Command.__init__ (self,
1481 "py-down",
1482 gdb.COMMAND_STACK,
1483 gdb.COMPLETE_NONE)
1484
1485
1486 def invoke(self, args, from_tty):
1487 move_in_stack(move_up=False)
1488
Victor Stinner50eb60e2010-04-20 22:32:07 +00001489# Not all builds of gdb have gdb.Frame.select
1490if hasattr(gdb.Frame, 'select'):
1491 PyUp()
1492 PyDown()
Benjamin Peterson6a6666a2010-04-11 21:49:28 +00001493
1494class PyBacktrace(gdb.Command):
1495 'Display the current python frame and all the frames within its call stack (if any)'
1496 def __init__(self):
1497 gdb.Command.__init__ (self,
1498 "py-bt",
1499 gdb.COMMAND_STACK,
1500 gdb.COMPLETE_NONE)
1501
1502
1503 def invoke(self, args, from_tty):
1504 frame = Frame.get_selected_python_frame()
1505 while frame:
1506 if frame.is_evalframeex():
1507 frame.print_summary()
1508 frame = frame.older()
1509
1510PyBacktrace()
1511
1512class PyPrint(gdb.Command):
1513 'Look up the given python variable name, and print it'
1514 def __init__(self):
1515 gdb.Command.__init__ (self,
1516 "py-print",
1517 gdb.COMMAND_DATA,
1518 gdb.COMPLETE_NONE)
1519
1520
1521 def invoke(self, args, from_tty):
1522 name = str(args)
1523
1524 frame = Frame.get_selected_python_frame()
1525 if not frame:
1526 print 'Unable to locate python frame'
1527 return
1528
1529 pyop_frame = frame.get_pyop()
1530 if not pyop_frame:
1531 print 'Unable to read information on python frame'
1532 return
1533
1534 pyop_var, scope = pyop_frame.get_var_by_name(name)
1535
1536 if pyop_var:
1537 print ('%s %r = %s'
1538 % (scope,
1539 name,
1540 pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
1541 else:
1542 print '%r not found' % name
1543
1544PyPrint()
1545
1546class PyLocals(gdb.Command):
1547 'Look up the given python variable name, and print it'
1548 def __init__(self):
1549 gdb.Command.__init__ (self,
1550 "py-locals",
1551 gdb.COMMAND_DATA,
1552 gdb.COMPLETE_NONE)
1553
1554
1555 def invoke(self, args, from_tty):
1556 name = str(args)
1557
1558 frame = Frame.get_selected_python_frame()
1559 if not frame:
1560 print 'Unable to locate python frame'
1561 return
1562
1563 pyop_frame = frame.get_pyop()
1564 if not pyop_frame:
1565 print 'Unable to read information on python frame'
1566 return
1567
1568 for pyop_name, pyop_value in pyop_frame.iter_locals():
1569 print ('%s = %s'
1570 % (pyop_name.proxyval(set()),
1571 pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
1572
1573PyLocals()