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