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