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