ยปCore Development>Code coverage>Tools/gdb/libpython.py

Python code coverage for Tools/gdb/libpython.py

#countcontent
1n/a#!/usr/bin/python
2n/a'''
3n/aFrom gdb 7 onwards, gdb's build can be configured --with-python, allowing gdb
4n/ato be extended with Python code e.g. for library-specific data visualizations,
5n/asuch as for the C++ STL types. Documentation on this API can be seen at:
6n/ahttp://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html
7n/a
8n/a
9n/aThis python module deals with the case when the process being debugged (the
10n/a"inferior process" in gdb parlance) is itself python, or more specifically,
11n/alinked against libpython. In this situation, almost every item of data is a
12n/a(PyObject*), and having the debugger merely print their addresses is not very
13n/aenlightening.
14n/a
15n/aThis module embeds knowledge about the implementation details of libpython so
16n/athat we can emit useful visualizations e.g. a string, a list, a dict, a frame
17n/agiving file/line information and the state of local variables
18n/a
19n/aIn particular, given a gdb.Value corresponding to a PyObject* in the inferior
20n/aprocess, we can generate a "proxy value" within the gdb process. For example,
21n/agiven a PyObject* in the inferior process that is in fact a PyListObject*
22n/aholding three PyObject* that turn out to be PyBytesObject* instances, we can
23n/agenerate a proxy value within the gdb process that is a list of bytes
24n/ainstances:
25n/a [b"foo", b"bar", b"baz"]
26n/a
27n/aDoing so can be expensive for complicated graphs of objects, and could take
28n/asome time, so we also have a "write_repr" method that writes a representation
29n/aof the data to a file-like object. This allows us to stop the traversal by
30n/ahaving the file-like object raise an exception if it gets too much data.
31n/a
32n/aWith both "proxyval" and "write_repr" we keep track of the set of all addresses
33n/avisited so far in the traversal, to avoid infinite recursion due to cycles in
34n/athe graph of object references.
35n/a
36n/aWe try to defer gdb.lookup_type() invocations for python types until as late as
37n/apossible: for a dynamically linked python binary, when the process starts in
38n/athe debugger, the libpython.so hasn't been dynamically loaded yet, so none of
39n/athe type names are known to the debugger
40n/a
41n/aThe module also extends gdb with some python-specific commands.
42n/a'''
43n/a
44n/a# NOTE: some gdbs are linked with Python 3, so this file should be dual-syntax
45n/a# compatible (2.6+ and 3.0+). See #19308.
46n/a
47n/afrom __future__ import print_function
48n/aimport gdb
49n/aimport os
50n/aimport locale
51n/aimport sys
52n/a
53n/aif sys.version_info[0] >= 3:
54n/a unichr = chr
55n/a xrange = range
56n/a long = int
57n/a
58n/a# Look up the gdb.Type for some standard types:
59n/a# Those need to be refreshed as types (pointer sizes) may change when
60n/a# gdb loads different executables
61n/a
62n/adef _type_char_ptr():
63n/a return gdb.lookup_type('char').pointer() # char*
64n/a
65n/a
66n/adef _type_unsigned_char_ptr():
67n/a return gdb.lookup_type('unsigned char').pointer() # unsigned char*
68n/a
69n/a
70n/adef _type_unsigned_short_ptr():
71n/a return gdb.lookup_type('unsigned short').pointer()
72n/a
73n/a
74n/adef _type_unsigned_int_ptr():
75n/a return gdb.lookup_type('unsigned int').pointer()
76n/a
77n/a
78n/adef _sizeof_void_p():
79n/a return gdb.lookup_type('void').pointer().sizeof
80n/a
81n/a
82n/a# value computed later, see PyUnicodeObjectPtr.proxy()
83n/a_is_pep393 = None
84n/a
85n/aPy_TPFLAGS_HEAPTYPE = (1 << 9)
86n/aPy_TPFLAGS_LONG_SUBCLASS = (1 << 24)
87n/aPy_TPFLAGS_LIST_SUBCLASS = (1 << 25)
88n/aPy_TPFLAGS_TUPLE_SUBCLASS = (1 << 26)
89n/aPy_TPFLAGS_BYTES_SUBCLASS = (1 << 27)
90n/aPy_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
91n/aPy_TPFLAGS_DICT_SUBCLASS = (1 << 29)
92n/aPy_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
93n/aPy_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
94n/a
95n/a
96n/aMAX_OUTPUT_LEN=1024
97n/a
98n/ahexdigits = "0123456789abcdef"
99n/a
100n/aENCODING = locale.getpreferredencoding()
101n/a
102n/aclass NullPyObjectPtr(RuntimeError):
103n/a pass
104n/a
105n/a
106n/adef safety_limit(val):
107n/a # Given an integer value from the process being debugged, limit it to some
108n/a # safety threshold so that arbitrary breakage within said process doesn't
109n/a # break the gdb process too much (e.g. sizes of iterations, sizes of lists)
110n/a return min(val, 1000)
111n/a
112n/a
113n/adef safe_range(val):
114n/a # As per range, but don't trust the value too much: cap it to a safety
115n/a # threshold in case the data was corrupted
116n/a return xrange(safety_limit(int(val)))
117n/a
118n/aif sys.version_info[0] >= 3:
119n/a def write_unicode(file, text):
120n/a file.write(text)
121n/aelse:
122n/a def write_unicode(file, text):
123n/a # Write a byte or unicode string to file. Unicode strings are encoded to
124n/a # ENCODING encoding with 'backslashreplace' error handler to avoid
125n/a # UnicodeEncodeError.
126n/a if isinstance(text, unicode):
127n/a text = text.encode(ENCODING, 'backslashreplace')
128n/a file.write(text)
129n/a
130n/atry:
131n/a os_fsencode = os.fsencode
132n/aexcept AttributeError:
133n/a def os_fsencode(filename):
134n/a if not isinstance(filename, unicode):
135n/a return filename
136n/a encoding = sys.getfilesystemencoding()
137n/a if encoding == 'mbcs':
138n/a # mbcs doesn't support surrogateescape
139n/a return filename.encode(encoding)
140n/a encoded = []
141n/a for char in filename:
142n/a # surrogateescape error handler
143n/a if 0xDC80 <= ord(char) <= 0xDCFF:
144n/a byte = chr(ord(char) - 0xDC00)
145n/a else:
146n/a byte = char.encode(encoding)
147n/a encoded.append(byte)
148n/a return ''.join(encoded)
149n/a
150n/aclass StringTruncated(RuntimeError):
151n/a pass
152n/a
153n/aclass TruncatedStringIO(object):
154n/a '''Similar to io.StringIO, but can truncate the output by raising a
155n/a StringTruncated exception'''
156n/a def __init__(self, maxlen=None):
157n/a self._val = ''
158n/a self.maxlen = maxlen
159n/a
160n/a def write(self, data):
161n/a if self.maxlen:
162n/a if len(data) + len(self._val) > self.maxlen:
163n/a # Truncation:
164n/a self._val += data[0:self.maxlen - len(self._val)]
165n/a raise StringTruncated()
166n/a
167n/a self._val += data
168n/a
169n/a def getvalue(self):
170n/a return self._val
171n/a
172n/aclass PyObjectPtr(object):
173n/a """
174n/a Class wrapping a gdb.Value that's either a (PyObject*) within the
175n/a inferior process, or some subclass pointer e.g. (PyBytesObject*)
176n/a
177n/a There will be a subclass for every refined PyObject type that we care
178n/a about.
179n/a
180n/a Note that at every stage the underlying pointer could be NULL, point
181n/a to corrupt data, etc; this is the debugger, after all.
182n/a """
183n/a _typename = 'PyObject'
184n/a
185n/a def __init__(self, gdbval, cast_to=None):
186n/a if cast_to:
187n/a self._gdbval = gdbval.cast(cast_to)
188n/a else:
189n/a self._gdbval = gdbval
190n/a
191n/a def field(self, name):
192n/a '''
193n/a Get the gdb.Value for the given field within the PyObject, coping with
194n/a some python 2 versus python 3 differences.
195n/a
196n/a Various libpython types are defined using the "PyObject_HEAD" and
197n/a "PyObject_VAR_HEAD" macros.
198n/a
199n/a In Python 2, this these are defined so that "ob_type" and (for a var
200n/a object) "ob_size" are fields of the type in question.
201n/a
202n/a In Python 3, this is defined as an embedded PyVarObject type thus:
203n/a PyVarObject ob_base;
204n/a so that the "ob_size" field is located insize the "ob_base" field, and
205n/a the "ob_type" is most easily accessed by casting back to a (PyObject*).
206n/a '''
207n/a if self.is_null():
208n/a raise NullPyObjectPtr(self)
209n/a
210n/a if name == 'ob_type':
211n/a pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type())
212n/a return pyo_ptr.dereference()[name]
213n/a
214n/a if name == 'ob_size':
215n/a pyo_ptr = self._gdbval.cast(PyVarObjectPtr.get_gdb_type())
216n/a return pyo_ptr.dereference()[name]
217n/a
218n/a # General case: look it up inside the object:
219n/a return self._gdbval.dereference()[name]
220n/a
221n/a def pyop_field(self, name):
222n/a '''
223n/a Get a PyObjectPtr for the given PyObject* field within this PyObject,
224n/a coping with some python 2 versus python 3 differences.
225n/a '''
226n/a return PyObjectPtr.from_pyobject_ptr(self.field(name))
227n/a
228n/a def write_field_repr(self, name, out, visited):
229n/a '''
230n/a Extract the PyObject* field named "name", and write its representation
231n/a to file-like object "out"
232n/a '''
233n/a field_obj = self.pyop_field(name)
234n/a field_obj.write_repr(out, visited)
235n/a
236n/a def get_truncated_repr(self, maxlen):
237n/a '''
238n/a Get a repr-like string for the data, but truncate it at "maxlen" bytes
239n/a (ending the object graph traversal as soon as you do)
240n/a '''
241n/a out = TruncatedStringIO(maxlen)
242n/a try:
243n/a self.write_repr(out, set())
244n/a except StringTruncated:
245n/a # Truncation occurred:
246n/a return out.getvalue() + '...(truncated)'
247n/a
248n/a # No truncation occurred:
249n/a return out.getvalue()
250n/a
251n/a def type(self):
252n/a return PyTypeObjectPtr(self.field('ob_type'))
253n/a
254n/a def is_null(self):
255n/a return 0 == long(self._gdbval)
256n/a
257n/a def is_optimized_out(self):
258n/a '''
259n/a Is the value of the underlying PyObject* visible to the debugger?
260n/a
261n/a This can vary with the precise version of the compiler used to build
262n/a Python, and the precise version of gdb.
263n/a
264n/a See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with
265n/a PyEval_EvalFrameEx's "f"
266n/a '''
267n/a return self._gdbval.is_optimized_out
268n/a
269n/a def safe_tp_name(self):
270n/a try:
271n/a return self.type().field('tp_name').string()
272n/a except NullPyObjectPtr:
273n/a # NULL tp_name?
274n/a return 'unknown'
275n/a except RuntimeError:
276n/a # Can't even read the object at all?
277n/a return 'unknown'
278n/a
279n/a def proxyval(self, visited):
280n/a '''
281n/a Scrape a value from the inferior process, and try to represent it
282n/a within the gdb process, whilst (hopefully) avoiding crashes when
283n/a the remote data is corrupt.
284n/a
285n/a Derived classes will override this.
286n/a
287n/a For example, a PyIntObject* with ob_ival 42 in the inferior process
288n/a should result in an int(42) in this process.
289n/a
290n/a visited: a set of all gdb.Value pyobject pointers already visited
291n/a whilst generating this value (to guard against infinite recursion when
292n/a visiting object graphs with loops). Analogous to Py_ReprEnter and
293n/a Py_ReprLeave
294n/a '''
295n/a
296n/a class FakeRepr(object):
297n/a """
298n/a Class representing a non-descript PyObject* value in the inferior
299n/a process for when we don't have a custom scraper, intended to have
300n/a a sane repr().
301n/a """
302n/a
303n/a def __init__(self, tp_name, address):
304n/a self.tp_name = tp_name
305n/a self.address = address
306n/a
307n/a def __repr__(self):
308n/a # For the NULL pointer, we have no way of knowing a type, so
309n/a # special-case it as per
310n/a # http://bugs.python.org/issue8032#msg100882
311n/a if self.address == 0:
312n/a return '0x0'
313n/a return '<%s at remote 0x%x>' % (self.tp_name, self.address)
314n/a
315n/a return FakeRepr(self.safe_tp_name(),
316n/a long(self._gdbval))
317n/a
318n/a def write_repr(self, out, visited):
319n/a '''
320n/a Write a string representation of the value scraped from the inferior
321n/a process to "out", a file-like object.
322n/a '''
323n/a # Default implementation: generate a proxy value and write its repr
324n/a # However, this could involve a lot of work for complicated objects,
325n/a # so for derived classes we specialize this
326n/a return out.write(repr(self.proxyval(visited)))
327n/a
328n/a @classmethod
329n/a def subclass_from_type(cls, t):
330n/a '''
331n/a Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
332n/a (PyTypeObject*), determine the corresponding subclass of PyObjectPtr
333n/a to use
334n/a
335n/a Ideally, we would look up the symbols for the global types, but that
336n/a isn't working yet:
337n/a (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
338n/a Traceback (most recent call last):
339n/a File "<string>", line 1, in <module>
340n/a NotImplementedError: Symbol type not yet supported in Python scripts.
341n/a Error while executing Python code.
342n/a
343n/a For now, we use tp_flags, after doing some string comparisons on the
344n/a tp_name for some special-cases that don't seem to be visible through
345n/a flags
346n/a '''
347n/a try:
348n/a tp_name = t.field('tp_name').string()
349n/a tp_flags = int(t.field('tp_flags'))
350n/a except RuntimeError:
351n/a # Handle any kind of error e.g. NULL ptrs by simply using the base
352n/a # class
353n/a return cls
354n/a
355n/a #print('tp_flags = 0x%08x' % tp_flags)
356n/a #print('tp_name = %r' % tp_name)
357n/a
358n/a name_map = {'bool': PyBoolObjectPtr,
359n/a 'classobj': PyClassObjectPtr,
360n/a 'NoneType': PyNoneStructPtr,
361n/a 'frame': PyFrameObjectPtr,
362n/a 'set' : PySetObjectPtr,
363n/a 'frozenset' : PySetObjectPtr,
364n/a 'builtin_function_or_method' : PyCFunctionObjectPtr,
365n/a 'method-wrapper': wrapperobject,
366n/a }
367n/a if tp_name in name_map:
368n/a return name_map[tp_name]
369n/a
370n/a if tp_flags & Py_TPFLAGS_HEAPTYPE:
371n/a return HeapTypeObjectPtr
372n/a
373n/a if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
374n/a return PyLongObjectPtr
375n/a if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
376n/a return PyListObjectPtr
377n/a if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
378n/a return PyTupleObjectPtr
379n/a if tp_flags & Py_TPFLAGS_BYTES_SUBCLASS:
380n/a return PyBytesObjectPtr
381n/a if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
382n/a return PyUnicodeObjectPtr
383n/a if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
384n/a return PyDictObjectPtr
385n/a if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
386n/a return PyBaseExceptionObjectPtr
387n/a #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
388n/a # return PyTypeObjectPtr
389n/a
390n/a # Use the base class:
391n/a return cls
392n/a
393n/a @classmethod
394n/a def from_pyobject_ptr(cls, gdbval):
395n/a '''
396n/a Try to locate the appropriate derived class dynamically, and cast
397n/a the pointer accordingly.
398n/a '''
399n/a try:
400n/a p = PyObjectPtr(gdbval)
401n/a cls = cls.subclass_from_type(p.type())
402n/a return cls(gdbval, cast_to=cls.get_gdb_type())
403n/a except RuntimeError:
404n/a # Handle any kind of error e.g. NULL ptrs by simply using the base
405n/a # class
406n/a pass
407n/a return cls(gdbval)
408n/a
409n/a @classmethod
410n/a def get_gdb_type(cls):
411n/a return gdb.lookup_type(cls._typename).pointer()
412n/a
413n/a def as_address(self):
414n/a return long(self._gdbval)
415n/a
416n/aclass PyVarObjectPtr(PyObjectPtr):
417n/a _typename = 'PyVarObject'
418n/a
419n/aclass ProxyAlreadyVisited(object):
420n/a '''
421n/a Placeholder proxy to use when protecting against infinite recursion due to
422n/a loops in the object graph.
423n/a
424n/a Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave
425n/a '''
426n/a def __init__(self, rep):
427n/a self._rep = rep
428n/a
429n/a def __repr__(self):
430n/a return self._rep
431n/a
432n/a
433n/adef _write_instance_repr(out, visited, name, pyop_attrdict, address):
434n/a '''Shared code for use by all classes:
435n/a write a representation to file-like object "out"'''
436n/a out.write('<')
437n/a out.write(name)
438n/a
439n/a # Write dictionary of instance attributes:
440n/a if isinstance(pyop_attrdict, PyDictObjectPtr):
441n/a out.write('(')
442n/a first = True
443n/a for pyop_arg, pyop_val in pyop_attrdict.iteritems():
444n/a if not first:
445n/a out.write(', ')
446n/a first = False
447n/a out.write(pyop_arg.proxyval(visited))
448n/a out.write('=')
449n/a pyop_val.write_repr(out, visited)
450n/a out.write(')')
451n/a out.write(' at remote 0x%x>' % address)
452n/a
453n/a
454n/aclass InstanceProxy(object):
455n/a
456n/a def __init__(self, cl_name, attrdict, address):
457n/a self.cl_name = cl_name
458n/a self.attrdict = attrdict
459n/a self.address = address
460n/a
461n/a def __repr__(self):
462n/a if isinstance(self.attrdict, dict):
463n/a kwargs = ', '.join(["%s=%r" % (arg, val)
464n/a for arg, val in self.attrdict.iteritems()])
465n/a return '<%s(%s) at remote 0x%x>' % (self.cl_name,
466n/a kwargs, self.address)
467n/a else:
468n/a return '<%s at remote 0x%x>' % (self.cl_name,
469n/a self.address)
470n/a
471n/adef _PyObject_VAR_SIZE(typeobj, nitems):
472n/a if _PyObject_VAR_SIZE._type_size_t is None:
473n/a _PyObject_VAR_SIZE._type_size_t = gdb.lookup_type('size_t')
474n/a
475n/a return ( ( typeobj.field('tp_basicsize') +
476n/a nitems * typeobj.field('tp_itemsize') +
477n/a (_sizeof_void_p() - 1)
478n/a ) & ~(_sizeof_void_p() - 1)
479n/a ).cast(_PyObject_VAR_SIZE._type_size_t)
480n/a_PyObject_VAR_SIZE._type_size_t = None
481n/a
482n/aclass HeapTypeObjectPtr(PyObjectPtr):
483n/a _typename = 'PyObject'
484n/a
485n/a def get_attr_dict(self):
486n/a '''
487n/a Get the PyDictObject ptr representing the attribute dictionary
488n/a (or None if there's a problem)
489n/a '''
490n/a try:
491n/a typeobj = self.type()
492n/a dictoffset = int_from_int(typeobj.field('tp_dictoffset'))
493n/a if dictoffset != 0:
494n/a if dictoffset < 0:
495n/a type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer()
496n/a tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size'])
497n/a if tsize < 0:
498n/a tsize = -tsize
499n/a size = _PyObject_VAR_SIZE(typeobj, tsize)
500n/a dictoffset += size
501n/a assert dictoffset > 0
502n/a assert dictoffset % _sizeof_void_p() == 0
503n/a
504n/a dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset
505n/a PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer()
506n/a dictptr = dictptr.cast(PyObjectPtrPtr)
507n/a return PyObjectPtr.from_pyobject_ptr(dictptr.dereference())
508n/a except RuntimeError:
509n/a # Corrupt data somewhere; fail safe
510n/a pass
511n/a
512n/a # Not found, or some kind of error:
513n/a return None
514n/a
515n/a def proxyval(self, visited):
516n/a '''
517n/a Support for classes.
518n/a
519n/a Currently we just locate the dictionary using a transliteration to
520n/a python of _PyObject_GetDictPtr, ignoring descriptors
521n/a '''
522n/a # Guard against infinite loops:
523n/a if self.as_address() in visited:
524n/a return ProxyAlreadyVisited('<...>')
525n/a visited.add(self.as_address())
526n/a
527n/a pyop_attr_dict = self.get_attr_dict()
528n/a if pyop_attr_dict:
529n/a attr_dict = pyop_attr_dict.proxyval(visited)
530n/a else:
531n/a attr_dict = {}
532n/a tp_name = self.safe_tp_name()
533n/a
534n/a # Class:
535n/a return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
536n/a
537n/a def write_repr(self, out, visited):
538n/a # Guard against infinite loops:
539n/a if self.as_address() in visited:
540n/a out.write('<...>')
541n/a return
542n/a visited.add(self.as_address())
543n/a
544n/a pyop_attrdict = self.get_attr_dict()
545n/a _write_instance_repr(out, visited,
546n/a self.safe_tp_name(), pyop_attrdict, self.as_address())
547n/a
548n/aclass ProxyException(Exception):
549n/a def __init__(self, tp_name, args):
550n/a self.tp_name = tp_name
551n/a self.args = args
552n/a
553n/a def __repr__(self):
554n/a return '%s%r' % (self.tp_name, self.args)
555n/a
556n/aclass PyBaseExceptionObjectPtr(PyObjectPtr):
557n/a """
558n/a Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
559n/a within the process being debugged.
560n/a """
561n/a _typename = 'PyBaseExceptionObject'
562n/a
563n/a def proxyval(self, visited):
564n/a # Guard against infinite loops:
565n/a if self.as_address() in visited:
566n/a return ProxyAlreadyVisited('(...)')
567n/a visited.add(self.as_address())
568n/a arg_proxy = self.pyop_field('args').proxyval(visited)
569n/a return ProxyException(self.safe_tp_name(),
570n/a arg_proxy)
571n/a
572n/a def write_repr(self, out, visited):
573n/a # Guard against infinite loops:
574n/a if self.as_address() in visited:
575n/a out.write('(...)')
576n/a return
577n/a visited.add(self.as_address())
578n/a
579n/a out.write(self.safe_tp_name())
580n/a self.write_field_repr('args', out, visited)
581n/a
582n/aclass PyClassObjectPtr(PyObjectPtr):
583n/a """
584n/a Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
585n/a instance within the process being debugged.
586n/a """
587n/a _typename = 'PyClassObject'
588n/a
589n/a
590n/aclass BuiltInFunctionProxy(object):
591n/a def __init__(self, ml_name):
592n/a self.ml_name = ml_name
593n/a
594n/a def __repr__(self):
595n/a return "<built-in function %s>" % self.ml_name
596n/a
597n/aclass BuiltInMethodProxy(object):
598n/a def __init__(self, ml_name, pyop_m_self):
599n/a self.ml_name = ml_name
600n/a self.pyop_m_self = pyop_m_self
601n/a
602n/a def __repr__(self):
603n/a return ('<built-in method %s of %s object at remote 0x%x>'
604n/a % (self.ml_name,
605n/a self.pyop_m_self.safe_tp_name(),
606n/a self.pyop_m_self.as_address())
607n/a )
608n/a
609n/aclass PyCFunctionObjectPtr(PyObjectPtr):
610n/a """
611n/a Class wrapping a gdb.Value that's a PyCFunctionObject*
612n/a (see Include/methodobject.h and Objects/methodobject.c)
613n/a """
614n/a _typename = 'PyCFunctionObject'
615n/a
616n/a def proxyval(self, visited):
617n/a m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*)
618n/a ml_name = m_ml['ml_name'].string()
619n/a
620n/a pyop_m_self = self.pyop_field('m_self')
621n/a if pyop_m_self.is_null():
622n/a return BuiltInFunctionProxy(ml_name)
623n/a else:
624n/a return BuiltInMethodProxy(ml_name, pyop_m_self)
625n/a
626n/a
627n/aclass PyCodeObjectPtr(PyObjectPtr):
628n/a """
629n/a Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance
630n/a within the process being debugged.
631n/a """
632n/a _typename = 'PyCodeObject'
633n/a
634n/a def addr2line(self, addrq):
635n/a '''
636n/a Get the line number for a given bytecode offset
637n/a
638n/a Analogous to PyCode_Addr2Line; translated from pseudocode in
639n/a Objects/lnotab_notes.txt
640n/a '''
641n/a co_lnotab = self.pyop_field('co_lnotab').proxyval(set())
642n/a
643n/a # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
644n/a # not 0, as lnotab_notes.txt has it:
645n/a lineno = int_from_int(self.field('co_firstlineno'))
646n/a
647n/a addr = 0
648n/a for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
649n/a addr += ord(addr_incr)
650n/a if addr > addrq:
651n/a return lineno
652n/a lineno += ord(line_incr)
653n/a return lineno
654n/a
655n/a
656n/aclass PyDictObjectPtr(PyObjectPtr):
657n/a """
658n/a Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance
659n/a within the process being debugged.
660n/a """
661n/a _typename = 'PyDictObject'
662n/a
663n/a def iteritems(self):
664n/a '''
665n/a Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
666n/a analogous to dict.iteritems()
667n/a '''
668n/a keys = self.field('ma_keys')
669n/a values = self.field('ma_values')
670n/a entries, nentries = self._get_entries(keys)
671n/a for i in safe_range(nentries):
672n/a ep = entries[i]
673n/a if long(values):
674n/a pyop_value = PyObjectPtr.from_pyobject_ptr(values[i])
675n/a else:
676n/a pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
677n/a if not pyop_value.is_null():
678n/a pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
679n/a yield (pyop_key, pyop_value)
680n/a
681n/a def proxyval(self, visited):
682n/a # Guard against infinite loops:
683n/a if self.as_address() in visited:
684n/a return ProxyAlreadyVisited('{...}')
685n/a visited.add(self.as_address())
686n/a
687n/a result = {}
688n/a for pyop_key, pyop_value in self.iteritems():
689n/a proxy_key = pyop_key.proxyval(visited)
690n/a proxy_value = pyop_value.proxyval(visited)
691n/a result[proxy_key] = proxy_value
692n/a return result
693n/a
694n/a def write_repr(self, out, visited):
695n/a # Guard against infinite loops:
696n/a if self.as_address() in visited:
697n/a out.write('{...}')
698n/a return
699n/a visited.add(self.as_address())
700n/a
701n/a out.write('{')
702n/a first = True
703n/a for pyop_key, pyop_value in self.iteritems():
704n/a if not first:
705n/a out.write(', ')
706n/a first = False
707n/a pyop_key.write_repr(out, visited)
708n/a out.write(': ')
709n/a pyop_value.write_repr(out, visited)
710n/a out.write('}')
711n/a
712n/a def _get_entries(self, keys):
713n/a dk_nentries = int(keys['dk_nentries'])
714n/a dk_size = int(keys['dk_size'])
715n/a try:
716n/a # <= Python 3.5
717n/a return keys['dk_entries'], dk_size
718n/a except gdb.error:
719n/a # >= Python 3.6
720n/a pass
721n/a
722n/a if dk_size <= 0xFF:
723n/a offset = dk_size
724n/a elif dk_size <= 0xFFFF:
725n/a offset = 2 * dk_size
726n/a elif dk_size <= 0xFFFFFFFF:
727n/a offset = 4 * dk_size
728n/a else:
729n/a offset = 8 * dk_size
730n/a
731n/a ent_addr = keys['dk_indices']['as_1'].address
732n/a ent_addr = ent_addr.cast(_type_unsigned_char_ptr()) + offset
733n/a ent_ptr_t = gdb.lookup_type('PyDictKeyEntry').pointer()
734n/a ent_addr = ent_addr.cast(ent_ptr_t)
735n/a
736n/a return ent_addr, dk_nentries
737n/a
738n/a
739n/aclass PyListObjectPtr(PyObjectPtr):
740n/a _typename = 'PyListObject'
741n/a
742n/a def __getitem__(self, i):
743n/a # Get the gdb.Value for the (PyObject*) with the given index:
744n/a field_ob_item = self.field('ob_item')
745n/a return field_ob_item[i]
746n/a
747n/a def proxyval(self, visited):
748n/a # Guard against infinite loops:
749n/a if self.as_address() in visited:
750n/a return ProxyAlreadyVisited('[...]')
751n/a visited.add(self.as_address())
752n/a
753n/a result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
754n/a for i in safe_range(int_from_int(self.field('ob_size')))]
755n/a return result
756n/a
757n/a def write_repr(self, out, visited):
758n/a # Guard against infinite loops:
759n/a if self.as_address() in visited:
760n/a out.write('[...]')
761n/a return
762n/a visited.add(self.as_address())
763n/a
764n/a out.write('[')
765n/a for i in safe_range(int_from_int(self.field('ob_size'))):
766n/a if i > 0:
767n/a out.write(', ')
768n/a element = PyObjectPtr.from_pyobject_ptr(self[i])
769n/a element.write_repr(out, visited)
770n/a out.write(']')
771n/a
772n/aclass PyLongObjectPtr(PyObjectPtr):
773n/a _typename = 'PyLongObject'
774n/a
775n/a def proxyval(self, visited):
776n/a '''
777n/a Python's Include/longobjrep.h has this declaration:
778n/a struct _longobject {
779n/a PyObject_VAR_HEAD
780n/a digit ob_digit[1];
781n/a };
782n/a
783n/a with this description:
784n/a The absolute value of a number is equal to
785n/a SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i)
786n/a Negative numbers are represented with ob_size < 0;
787n/a zero is represented by ob_size == 0.
788n/a
789n/a where SHIFT can be either:
790n/a #define PyLong_SHIFT 30
791n/a #define PyLong_SHIFT 15
792n/a '''
793n/a ob_size = long(self.field('ob_size'))
794n/a if ob_size == 0:
795n/a return 0
796n/a
797n/a ob_digit = self.field('ob_digit')
798n/a
799n/a if gdb.lookup_type('digit').sizeof == 2:
800n/a SHIFT = 15
801n/a else:
802n/a SHIFT = 30
803n/a
804n/a digits = [long(ob_digit[i]) * 2**(SHIFT*i)
805n/a for i in safe_range(abs(ob_size))]
806n/a result = sum(digits)
807n/a if ob_size < 0:
808n/a result = -result
809n/a return result
810n/a
811n/a def write_repr(self, out, visited):
812n/a # Write this out as a Python 3 int literal, i.e. without the "L" suffix
813n/a proxy = self.proxyval(visited)
814n/a out.write("%s" % proxy)
815n/a
816n/a
817n/aclass PyBoolObjectPtr(PyLongObjectPtr):
818n/a """
819n/a Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
820n/a <bool> instances (Py_True/Py_False) within the process being debugged.
821n/a """
822n/a def proxyval(self, visited):
823n/a if PyLongObjectPtr.proxyval(self, visited):
824n/a return True
825n/a else:
826n/a return False
827n/a
828n/aclass PyNoneStructPtr(PyObjectPtr):
829n/a """
830n/a Class wrapping a gdb.Value that's a PyObject* pointing to the
831n/a singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type
832n/a """
833n/a _typename = 'PyObject'
834n/a
835n/a def proxyval(self, visited):
836n/a return None
837n/a
838n/a
839n/aclass PyFrameObjectPtr(PyObjectPtr):
840n/a _typename = 'PyFrameObject'
841n/a
842n/a def __init__(self, gdbval, cast_to=None):
843n/a PyObjectPtr.__init__(self, gdbval, cast_to)
844n/a
845n/a if not self.is_optimized_out():
846n/a self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
847n/a self.co_name = self.co.pyop_field('co_name')
848n/a self.co_filename = self.co.pyop_field('co_filename')
849n/a
850n/a self.f_lineno = int_from_int(self.field('f_lineno'))
851n/a self.f_lasti = int_from_int(self.field('f_lasti'))
852n/a self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
853n/a self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames'))
854n/a
855n/a def iter_locals(self):
856n/a '''
857n/a Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
858n/a the local variables of this frame
859n/a '''
860n/a if self.is_optimized_out():
861n/a return
862n/a
863n/a f_localsplus = self.field('f_localsplus')
864n/a for i in safe_range(self.co_nlocals):
865n/a pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
866n/a if not pyop_value.is_null():
867n/a pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i])
868n/a yield (pyop_name, pyop_value)
869n/a
870n/a def iter_globals(self):
871n/a '''
872n/a Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
873n/a the global variables of this frame
874n/a '''
875n/a if self.is_optimized_out():
876n/a return ()
877n/a
878n/a pyop_globals = self.pyop_field('f_globals')
879n/a return pyop_globals.iteritems()
880n/a
881n/a def iter_builtins(self):
882n/a '''
883n/a Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
884n/a the builtin variables
885n/a '''
886n/a if self.is_optimized_out():
887n/a return ()
888n/a
889n/a pyop_builtins = self.pyop_field('f_builtins')
890n/a return pyop_builtins.iteritems()
891n/a
892n/a def get_var_by_name(self, name):
893n/a '''
894n/a Look for the named local variable, returning a (PyObjectPtr, scope) pair
895n/a where scope is a string 'local', 'global', 'builtin'
896n/a
897n/a If not found, return (None, None)
898n/a '''
899n/a for pyop_name, pyop_value in self.iter_locals():
900n/a if name == pyop_name.proxyval(set()):
901n/a return pyop_value, 'local'
902n/a for pyop_name, pyop_value in self.iter_globals():
903n/a if name == pyop_name.proxyval(set()):
904n/a return pyop_value, 'global'
905n/a for pyop_name, pyop_value in self.iter_builtins():
906n/a if name == pyop_name.proxyval(set()):
907n/a return pyop_value, 'builtin'
908n/a return None, None
909n/a
910n/a def filename(self):
911n/a '''Get the path of the current Python source file, as a string'''
912n/a if self.is_optimized_out():
913n/a return '(frame information optimized out)'
914n/a return self.co_filename.proxyval(set())
915n/a
916n/a def current_line_num(self):
917n/a '''Get current line number as an integer (1-based)
918n/a
919n/a Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
920n/a
921n/a See Objects/lnotab_notes.txt
922n/a '''
923n/a if self.is_optimized_out():
924n/a return None
925n/a f_trace = self.field('f_trace')
926n/a if long(f_trace) != 0:
927n/a # we have a non-NULL f_trace:
928n/a return self.f_lineno
929n/a else:
930n/a #try:
931n/a return self.co.addr2line(self.f_lasti)
932n/a #except ValueError:
933n/a # return self.f_lineno
934n/a
935n/a def current_line(self):
936n/a '''Get the text of the current source line as a string, with a trailing
937n/a newline character'''
938n/a if self.is_optimized_out():
939n/a return '(frame information optimized out)'
940n/a filename = self.filename()
941n/a try:
942n/a f = open(os_fsencode(filename), 'r')
943n/a except IOError:
944n/a return None
945n/a with f:
946n/a all_lines = f.readlines()
947n/a # Convert from 1-based current_line_num to 0-based list offset:
948n/a return all_lines[self.current_line_num()-1]
949n/a
950n/a def write_repr(self, out, visited):
951n/a if self.is_optimized_out():
952n/a out.write('(frame information optimized out)')
953n/a return
954n/a out.write('Frame 0x%x, for file %s, line %i, in %s ('
955n/a % (self.as_address(),
956n/a self.co_filename.proxyval(visited),
957n/a self.current_line_num(),
958n/a self.co_name.proxyval(visited)))
959n/a first = True
960n/a for pyop_name, pyop_value in self.iter_locals():
961n/a if not first:
962n/a out.write(', ')
963n/a first = False
964n/a
965n/a out.write(pyop_name.proxyval(visited))
966n/a out.write('=')
967n/a pyop_value.write_repr(out, visited)
968n/a
969n/a out.write(')')
970n/a
971n/a def print_traceback(self):
972n/a if self.is_optimized_out():
973n/a sys.stdout.write(' (frame information optimized out)\n')
974n/a return
975n/a visited = set()
976n/a sys.stdout.write(' File "%s", line %i, in %s\n'
977n/a % (self.co_filename.proxyval(visited),
978n/a self.current_line_num(),
979n/a self.co_name.proxyval(visited)))
980n/a
981n/aclass PySetObjectPtr(PyObjectPtr):
982n/a _typename = 'PySetObject'
983n/a
984n/a @classmethod
985n/a def _dummy_key(self):
986n/a return gdb.lookup_global_symbol('_PySet_Dummy').value()
987n/a
988n/a def __iter__(self):
989n/a dummy_ptr = self._dummy_key()
990n/a table = self.field('table')
991n/a for i in safe_range(self.field('mask') + 1):
992n/a setentry = table[i]
993n/a key = setentry['key']
994n/a if key != 0 and key != dummy_ptr:
995n/a yield PyObjectPtr.from_pyobject_ptr(key)
996n/a
997n/a def proxyval(self, visited):
998n/a # Guard against infinite loops:
999n/a if self.as_address() in visited:
1000n/a return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
1001n/a visited.add(self.as_address())
1002n/a
1003n/a members = (key.proxyval(visited) for key in self)
1004n/a if self.safe_tp_name() == 'frozenset':
1005n/a return frozenset(members)
1006n/a else:
1007n/a return set(members)
1008n/a
1009n/a def write_repr(self, out, visited):
1010n/a # Emulate Python 3's set_repr
1011n/a tp_name = self.safe_tp_name()
1012n/a
1013n/a # Guard against infinite loops:
1014n/a if self.as_address() in visited:
1015n/a out.write('(...)')
1016n/a return
1017n/a visited.add(self.as_address())
1018n/a
1019n/a # Python 3's set_repr special-cases the empty set:
1020n/a if not self.field('used'):
1021n/a out.write(tp_name)
1022n/a out.write('()')
1023n/a return
1024n/a
1025n/a # Python 3 uses {} for set literals:
1026n/a if tp_name != 'set':
1027n/a out.write(tp_name)
1028n/a out.write('(')
1029n/a
1030n/a out.write('{')
1031n/a first = True
1032n/a for key in self:
1033n/a if not first:
1034n/a out.write(', ')
1035n/a first = False
1036n/a key.write_repr(out, visited)
1037n/a out.write('}')
1038n/a
1039n/a if tp_name != 'set':
1040n/a out.write(')')
1041n/a
1042n/a
1043n/aclass PyBytesObjectPtr(PyObjectPtr):
1044n/a _typename = 'PyBytesObject'
1045n/a
1046n/a def __str__(self):
1047n/a field_ob_size = self.field('ob_size')
1048n/a field_ob_sval = self.field('ob_sval')
1049n/a char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr())
1050n/a return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
1051n/a
1052n/a def proxyval(self, visited):
1053n/a return str(self)
1054n/a
1055n/a def write_repr(self, out, visited):
1056n/a # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix
1057n/a
1058n/a # Get a PyStringObject* within the Python 2 gdb process:
1059n/a proxy = self.proxyval(visited)
1060n/a
1061n/a # Transliteration of Python 3's Objects/bytesobject.c:PyBytes_Repr
1062n/a # to Python 2 code:
1063n/a quote = "'"
1064n/a if "'" in proxy and not '"' in proxy:
1065n/a quote = '"'
1066n/a out.write('b')
1067n/a out.write(quote)
1068n/a for byte in proxy:
1069n/a if byte == quote or byte == '\\':
1070n/a out.write('\\')
1071n/a out.write(byte)
1072n/a elif byte == '\t':
1073n/a out.write('\\t')
1074n/a elif byte == '\n':
1075n/a out.write('\\n')
1076n/a elif byte == '\r':
1077n/a out.write('\\r')
1078n/a elif byte < ' ' or ord(byte) >= 0x7f:
1079n/a out.write('\\x')
1080n/a out.write(hexdigits[(ord(byte) & 0xf0) >> 4])
1081n/a out.write(hexdigits[ord(byte) & 0xf])
1082n/a else:
1083n/a out.write(byte)
1084n/a out.write(quote)
1085n/a
1086n/aclass PyTupleObjectPtr(PyObjectPtr):
1087n/a _typename = 'PyTupleObject'
1088n/a
1089n/a def __getitem__(self, i):
1090n/a # Get the gdb.Value for the (PyObject*) with the given index:
1091n/a field_ob_item = self.field('ob_item')
1092n/a return field_ob_item[i]
1093n/a
1094n/a def proxyval(self, visited):
1095n/a # Guard against infinite loops:
1096n/a if self.as_address() in visited:
1097n/a return ProxyAlreadyVisited('(...)')
1098n/a visited.add(self.as_address())
1099n/a
1100n/a result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
1101n/a for i in safe_range(int_from_int(self.field('ob_size')))])
1102n/a return result
1103n/a
1104n/a def write_repr(self, out, visited):
1105n/a # Guard against infinite loops:
1106n/a if self.as_address() in visited:
1107n/a out.write('(...)')
1108n/a return
1109n/a visited.add(self.as_address())
1110n/a
1111n/a out.write('(')
1112n/a for i in safe_range(int_from_int(self.field('ob_size'))):
1113n/a if i > 0:
1114n/a out.write(', ')
1115n/a element = PyObjectPtr.from_pyobject_ptr(self[i])
1116n/a element.write_repr(out, visited)
1117n/a if self.field('ob_size') == 1:
1118n/a out.write(',)')
1119n/a else:
1120n/a out.write(')')
1121n/a
1122n/aclass PyTypeObjectPtr(PyObjectPtr):
1123n/a _typename = 'PyTypeObject'
1124n/a
1125n/a
1126n/adef _unichr_is_printable(char):
1127n/a # Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
1128n/a if char == u" ":
1129n/a return True
1130n/a import unicodedata
1131n/a return unicodedata.category(char) not in ("C", "Z")
1132n/a
1133n/aif sys.maxunicode >= 0x10000:
1134n/a _unichr = unichr
1135n/aelse:
1136n/a # Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb
1137n/a def _unichr(x):
1138n/a if x < 0x10000:
1139n/a return unichr(x)
1140n/a x -= 0x10000
1141n/a ch1 = 0xD800 | (x >> 10)
1142n/a ch2 = 0xDC00 | (x & 0x3FF)
1143n/a return unichr(ch1) + unichr(ch2)
1144n/a
1145n/a
1146n/aclass PyUnicodeObjectPtr(PyObjectPtr):
1147n/a _typename = 'PyUnicodeObject'
1148n/a
1149n/a def char_width(self):
1150n/a _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE')
1151n/a return _type_Py_UNICODE.sizeof
1152n/a
1153n/a def proxyval(self, visited):
1154n/a global _is_pep393
1155n/a if _is_pep393 is None:
1156n/a fields = gdb.lookup_type('PyUnicodeObject').target().fields()
1157n/a _is_pep393 = 'data' in [f.name for f in fields]
1158n/a if _is_pep393:
1159n/a # Python 3.3 and newer
1160n/a may_have_surrogates = False
1161n/a compact = self.field('_base')
1162n/a ascii = compact['_base']
1163n/a state = ascii['state']
1164n/a is_compact_ascii = (int(state['ascii']) and int(state['compact']))
1165n/a if not int(state['ready']):
1166n/a # string is not ready
1167n/a field_length = long(compact['wstr_length'])
1168n/a may_have_surrogates = True
1169n/a field_str = ascii['wstr']
1170n/a else:
1171n/a field_length = long(ascii['length'])
1172n/a if is_compact_ascii:
1173n/a field_str = ascii.address + 1
1174n/a elif int(state['compact']):
1175n/a field_str = compact.address + 1
1176n/a else:
1177n/a field_str = self.field('data')['any']
1178n/a repr_kind = int(state['kind'])
1179n/a if repr_kind == 1:
1180n/a field_str = field_str.cast(_type_unsigned_char_ptr())
1181n/a elif repr_kind == 2:
1182n/a field_str = field_str.cast(_type_unsigned_short_ptr())
1183n/a elif repr_kind == 4:
1184n/a field_str = field_str.cast(_type_unsigned_int_ptr())
1185n/a else:
1186n/a # Python 3.2 and earlier
1187n/a field_length = long(self.field('length'))
1188n/a field_str = self.field('str')
1189n/a may_have_surrogates = self.char_width() == 2
1190n/a
1191n/a # Gather a list of ints from the Py_UNICODE array; these are either
1192n/a # UCS-1, UCS-2 or UCS-4 code points:
1193n/a if not may_have_surrogates:
1194n/a Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
1195n/a else:
1196n/a # A more elaborate routine if sizeof(Py_UNICODE) is 2 in the
1197n/a # inferior process: we must join surrogate pairs.
1198n/a Py_UNICODEs = []
1199n/a i = 0
1200n/a limit = safety_limit(field_length)
1201n/a while i < limit:
1202n/a ucs = int(field_str[i])
1203n/a i += 1
1204n/a if ucs < 0xD800 or ucs >= 0xDC00 or i == field_length:
1205n/a Py_UNICODEs.append(ucs)
1206n/a continue
1207n/a # This could be a surrogate pair.
1208n/a ucs2 = int(field_str[i])
1209n/a if ucs2 < 0xDC00 or ucs2 > 0xDFFF:
1210n/a continue
1211n/a code = (ucs & 0x03FF) << 10
1212n/a code |= ucs2 & 0x03FF
1213n/a code += 0x00010000
1214n/a Py_UNICODEs.append(code)
1215n/a i += 1
1216n/a
1217n/a # Convert the int code points to unicode characters, and generate a
1218n/a # local unicode instance.
1219n/a # This splits surrogate pairs if sizeof(Py_UNICODE) is 2 here (in gdb).
1220n/a result = u''.join([
1221n/a (_unichr(ucs) if ucs <= 0x10ffff else '\ufffd')
1222n/a for ucs in Py_UNICODEs])
1223n/a return result
1224n/a
1225n/a def write_repr(self, out, visited):
1226n/a # Write this out as a Python 3 str literal, i.e. without a "u" prefix
1227n/a
1228n/a # Get a PyUnicodeObject* within the Python 2 gdb process:
1229n/a proxy = self.proxyval(visited)
1230n/a
1231n/a # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr
1232n/a # to Python 2:
1233n/a if "'" in proxy and '"' not in proxy:
1234n/a quote = '"'
1235n/a else:
1236n/a quote = "'"
1237n/a out.write(quote)
1238n/a
1239n/a i = 0
1240n/a while i < len(proxy):
1241n/a ch = proxy[i]
1242n/a i += 1
1243n/a
1244n/a # Escape quotes and backslashes
1245n/a if ch == quote or ch == '\\':
1246n/a out.write('\\')
1247n/a out.write(ch)
1248n/a
1249n/a # Map special whitespace to '\t', \n', '\r'
1250n/a elif ch == '\t':
1251n/a out.write('\\t')
1252n/a elif ch == '\n':
1253n/a out.write('\\n')
1254n/a elif ch == '\r':
1255n/a out.write('\\r')
1256n/a
1257n/a # Map non-printable US ASCII to '\xhh' */
1258n/a elif ch < ' ' or ch == 0x7F:
1259n/a out.write('\\x')
1260n/a out.write(hexdigits[(ord(ch) >> 4) & 0x000F])
1261n/a out.write(hexdigits[ord(ch) & 0x000F])
1262n/a
1263n/a # Copy ASCII characters as-is
1264n/a elif ord(ch) < 0x7F:
1265n/a out.write(ch)
1266n/a
1267n/a # Non-ASCII characters
1268n/a else:
1269n/a ucs = ch
1270n/a ch2 = None
1271n/a if sys.maxunicode < 0x10000:
1272n/a # If sizeof(Py_UNICODE) is 2 here (in gdb), join
1273n/a # surrogate pairs before calling _unichr_is_printable.
1274n/a if (i < len(proxy)
1275n/a and 0xD800 <= ord(ch) < 0xDC00 \
1276n/a and 0xDC00 <= ord(proxy[i]) <= 0xDFFF):
1277n/a ch2 = proxy[i]
1278n/a ucs = ch + ch2
1279n/a i += 1
1280n/a
1281n/a # Unfortuately, Python 2's unicode type doesn't seem
1282n/a # to expose the "isprintable" method
1283n/a printable = _unichr_is_printable(ucs)
1284n/a if printable:
1285n/a try:
1286n/a ucs.encode(ENCODING)
1287n/a except UnicodeEncodeError:
1288n/a printable = False
1289n/a
1290n/a # Map Unicode whitespace and control characters
1291n/a # (categories Z* and C* except ASCII space)
1292n/a if not printable:
1293n/a if ch2 is not None:
1294n/a # Match Python 3's representation of non-printable
1295n/a # wide characters.
1296n/a code = (ord(ch) & 0x03FF) << 10
1297n/a code |= ord(ch2) & 0x03FF
1298n/a code += 0x00010000
1299n/a else:
1300n/a code = ord(ucs)
1301n/a
1302n/a # Map 8-bit characters to '\\xhh'
1303n/a if code <= 0xff:
1304n/a out.write('\\x')
1305n/a out.write(hexdigits[(code >> 4) & 0x000F])
1306n/a out.write(hexdigits[code & 0x000F])
1307n/a # Map 21-bit characters to '\U00xxxxxx'
1308n/a elif code >= 0x10000:
1309n/a out.write('\\U')
1310n/a out.write(hexdigits[(code >> 28) & 0x0000000F])
1311n/a out.write(hexdigits[(code >> 24) & 0x0000000F])
1312n/a out.write(hexdigits[(code >> 20) & 0x0000000F])
1313n/a out.write(hexdigits[(code >> 16) & 0x0000000F])
1314n/a out.write(hexdigits[(code >> 12) & 0x0000000F])
1315n/a out.write(hexdigits[(code >> 8) & 0x0000000F])
1316n/a out.write(hexdigits[(code >> 4) & 0x0000000F])
1317n/a out.write(hexdigits[code & 0x0000000F])
1318n/a # Map 16-bit characters to '\uxxxx'
1319n/a else:
1320n/a out.write('\\u')
1321n/a out.write(hexdigits[(code >> 12) & 0x000F])
1322n/a out.write(hexdigits[(code >> 8) & 0x000F])
1323n/a out.write(hexdigits[(code >> 4) & 0x000F])
1324n/a out.write(hexdigits[code & 0x000F])
1325n/a else:
1326n/a # Copy characters as-is
1327n/a out.write(ch)
1328n/a if ch2 is not None:
1329n/a out.write(ch2)
1330n/a
1331n/a out.write(quote)
1332n/a
1333n/a
1334n/aclass wrapperobject(PyObjectPtr):
1335n/a _typename = 'wrapperobject'
1336n/a
1337n/a def safe_name(self):
1338n/a try:
1339n/a name = self.field('descr')['d_base']['name'].string()
1340n/a return repr(name)
1341n/a except (NullPyObjectPtr, RuntimeError):
1342n/a return '<unknown name>'
1343n/a
1344n/a def safe_tp_name(self):
1345n/a try:
1346n/a return self.field('self')['ob_type']['tp_name'].string()
1347n/a except (NullPyObjectPtr, RuntimeError):
1348n/a return '<unknown tp_name>'
1349n/a
1350n/a def safe_self_addresss(self):
1351n/a try:
1352n/a address = long(self.field('self'))
1353n/a return '%#x' % address
1354n/a except (NullPyObjectPtr, RuntimeError):
1355n/a return '<failed to get self address>'
1356n/a
1357n/a def proxyval(self, visited):
1358n/a name = self.safe_name()
1359n/a tp_name = self.safe_tp_name()
1360n/a self_address = self.safe_self_addresss()
1361n/a return ("<method-wrapper %s of %s object at %s>"
1362n/a % (name, tp_name, self_address))
1363n/a
1364n/a def write_repr(self, out, visited):
1365n/a proxy = self.proxyval(visited)
1366n/a out.write(proxy)
1367n/a
1368n/a
1369n/adef int_from_int(gdbval):
1370n/a return int(str(gdbval))
1371n/a
1372n/a
1373n/adef stringify(val):
1374n/a # TODO: repr() puts everything on one line; pformat can be nicer, but
1375n/a # can lead to v.long results; this function isolates the choice
1376n/a if True:
1377n/a return repr(val)
1378n/a else:
1379n/a from pprint import pformat
1380n/a return pformat(val)
1381n/a
1382n/a
1383n/aclass PyObjectPtrPrinter:
1384n/a "Prints a (PyObject*)"
1385n/a
1386n/a def __init__ (self, gdbval):
1387n/a self.gdbval = gdbval
1388n/a
1389n/a def to_string (self):
1390n/a pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval)
1391n/a if True:
1392n/a return pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1393n/a else:
1394n/a # Generate full proxy value then stringify it.
1395n/a # Doing so could be expensive
1396n/a proxyval = pyop.proxyval(set())
1397n/a return stringify(proxyval)
1398n/a
1399n/adef pretty_printer_lookup(gdbval):
1400n/a type = gdbval.type.unqualified()
1401n/a if type.code != gdb.TYPE_CODE_PTR:
1402n/a return None
1403n/a
1404n/a type = type.target().unqualified()
1405n/a t = str(type)
1406n/a if t in ("PyObject", "PyFrameObject", "PyUnicodeObject", "wrapperobject"):
1407n/a return PyObjectPtrPrinter(gdbval)
1408n/a
1409n/a"""
1410n/aDuring development, I've been manually invoking the code in this way:
1411n/a(gdb) python
1412n/a
1413n/aimport sys
1414n/asys.path.append('/home/david/coding/python-gdb')
1415n/aimport libpython
1416n/aend
1417n/a
1418n/athen reloading it after each edit like this:
1419n/a(gdb) python reload(libpython)
1420n/a
1421n/aThe following code should ensure that the prettyprinter is registered
1422n/aif the code is autoloaded by gdb when visiting libpython.so, provided
1423n/athat this python file is installed to the same path as the library (or its
1424n/a.debug file) plus a "-gdb.py" suffix, e.g:
1425n/a /usr/lib/libpython2.6.so.1.0-gdb.py
1426n/a /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
1427n/a"""
1428n/adef register (obj):
1429n/a if obj is None:
1430n/a obj = gdb
1431n/a
1432n/a # Wire up the pretty-printer
1433n/a obj.pretty_printers.append(pretty_printer_lookup)
1434n/a
1435n/aregister (gdb.current_objfile ())
1436n/a
1437n/a
1438n/a
1439n/a# Unfortunately, the exact API exposed by the gdb module varies somewhat
1440n/a# from build to build
1441n/a# See http://bugs.python.org/issue8279?#msg102276
1442n/a
1443n/aclass Frame(object):
1444n/a '''
1445n/a Wrapper for gdb.Frame, adding various methods
1446n/a '''
1447n/a def __init__(self, gdbframe):
1448n/a self._gdbframe = gdbframe
1449n/a
1450n/a def older(self):
1451n/a older = self._gdbframe.older()
1452n/a if older:
1453n/a return Frame(older)
1454n/a else:
1455n/a return None
1456n/a
1457n/a def newer(self):
1458n/a newer = self._gdbframe.newer()
1459n/a if newer:
1460n/a return Frame(newer)
1461n/a else:
1462n/a return None
1463n/a
1464n/a def select(self):
1465n/a '''If supported, select this frame and return True; return False if unsupported
1466n/a
1467n/a Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12
1468n/a onwards, but absent on Ubuntu buildbot'''
1469n/a if not hasattr(self._gdbframe, 'select'):
1470n/a print ('Unable to select frame: '
1471n/a 'this build of gdb does not expose a gdb.Frame.select method')
1472n/a return False
1473n/a self._gdbframe.select()
1474n/a return True
1475n/a
1476n/a def get_index(self):
1477n/a '''Calculate index of frame, starting at 0 for the newest frame within
1478n/a this thread'''
1479n/a index = 0
1480n/a # Go down until you reach the newest frame:
1481n/a iter_frame = self
1482n/a while iter_frame.newer():
1483n/a index += 1
1484n/a iter_frame = iter_frame.newer()
1485n/a return index
1486n/a
1487n/a # We divide frames into:
1488n/a # - "python frames":
1489n/a # - "bytecode frames" i.e. PyEval_EvalFrameEx
1490n/a # - "other python frames": things that are of interest from a python
1491n/a # POV, but aren't bytecode (e.g. GC, GIL)
1492n/a # - everything else
1493n/a
1494n/a def is_python_frame(self):
1495n/a '''Is this a PyEval_EvalFrameEx frame, or some other important
1496n/a frame? (see is_other_python_frame for what "important" means in this
1497n/a context)'''
1498n/a if self.is_evalframeex():
1499n/a return True
1500n/a if self.is_other_python_frame():
1501n/a return True
1502n/a return False
1503n/a
1504n/a def is_evalframeex(self):
1505n/a '''Is this a PyEval_EvalFrameEx frame?'''
1506n/a if self._gdbframe.name() == 'PyEval_EvalFrameEx':
1507n/a '''
1508n/a I believe we also need to filter on the inline
1509n/a struct frame_id.inline_depth, only regarding frames with
1510n/a an inline depth of 0 as actually being this function
1511n/a
1512n/a So we reject those with type gdb.INLINE_FRAME
1513n/a '''
1514n/a if self._gdbframe.type() == gdb.NORMAL_FRAME:
1515n/a # We have a PyEval_EvalFrameEx frame:
1516n/a return True
1517n/a
1518n/a return False
1519n/a
1520n/a def is_other_python_frame(self):
1521n/a '''Is this frame worth displaying in python backtraces?
1522n/a Examples:
1523n/a - waiting on the GIL
1524n/a - garbage-collecting
1525n/a - within a CFunction
1526n/a If it is, return a descriptive string
1527n/a For other frames, return False
1528n/a '''
1529n/a if self.is_waiting_for_gil():
1530n/a return 'Waiting for the GIL'
1531n/a
1532n/a if self.is_gc_collect():
1533n/a return 'Garbage-collecting'
1534n/a
1535n/a # Detect invocations of PyCFunction instances:
1536n/a frame = self._gdbframe
1537n/a caller = frame.name()
1538n/a if not caller:
1539n/a return False
1540n/a
1541n/a if caller in ('_PyCFunction_FastCallDict',
1542n/a '_PyCFunction_FastCallKeywords'):
1543n/a arg_name = 'func'
1544n/a # Within that frame:
1545n/a # "func" is the local containing the PyObject* of the
1546n/a # PyCFunctionObject instance
1547n/a # "f" is the same value, but cast to (PyCFunctionObject*)
1548n/a # "self" is the (PyObject*) of the 'self'
1549n/a try:
1550n/a # Use the prettyprinter for the func:
1551n/a func = frame.read_var(arg_name)
1552n/a return str(func)
1553n/a except RuntimeError:
1554n/a return 'PyCFunction invocation (unable to read %s)' % arg_name
1555n/a
1556n/a if caller == 'wrapper_call':
1557n/a try:
1558n/a func = frame.read_var('wp')
1559n/a return str(func)
1560n/a except RuntimeError:
1561n/a return '<wrapper_call invocation>'
1562n/a
1563n/a # This frame isn't worth reporting:
1564n/a return False
1565n/a
1566n/a def is_waiting_for_gil(self):
1567n/a '''Is this frame waiting on the GIL?'''
1568n/a # This assumes the _POSIX_THREADS version of Python/ceval_gil.h:
1569n/a name = self._gdbframe.name()
1570n/a if name:
1571n/a return 'pthread_cond_timedwait' in name
1572n/a
1573n/a def is_gc_collect(self):
1574n/a '''Is this frame "collect" within the garbage-collector?'''
1575n/a return self._gdbframe.name() == 'collect'
1576n/a
1577n/a def get_pyop(self):
1578n/a try:
1579n/a f = self._gdbframe.read_var('f')
1580n/a frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1581n/a if not frame.is_optimized_out():
1582n/a return frame
1583n/a # gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
1584n/a # because it was "optimized out". Try to get "f" from the frame
1585n/a # of the caller, PyEval_EvalCodeEx().
1586n/a orig_frame = frame
1587n/a caller = self._gdbframe.older()
1588n/a if caller:
1589n/a f = caller.read_var('f')
1590n/a frame = PyFrameObjectPtr.from_pyobject_ptr(f)
1591n/a if not frame.is_optimized_out():
1592n/a return frame
1593n/a return orig_frame
1594n/a except ValueError:
1595n/a return None
1596n/a
1597n/a @classmethod
1598n/a def get_selected_frame(cls):
1599n/a _gdbframe = gdb.selected_frame()
1600n/a if _gdbframe:
1601n/a return Frame(_gdbframe)
1602n/a return None
1603n/a
1604n/a @classmethod
1605n/a def get_selected_python_frame(cls):
1606n/a '''Try to obtain the Frame for the python-related code in the selected
1607n/a frame, or None'''
1608n/a try:
1609n/a frame = cls.get_selected_frame()
1610n/a except gdb.error:
1611n/a # No frame: Python didn't start yet
1612n/a return None
1613n/a
1614n/a while frame:
1615n/a if frame.is_python_frame():
1616n/a return frame
1617n/a frame = frame.older()
1618n/a
1619n/a # Not found:
1620n/a return None
1621n/a
1622n/a @classmethod
1623n/a def get_selected_bytecode_frame(cls):
1624n/a '''Try to obtain the Frame for the python bytecode interpreter in the
1625n/a selected GDB frame, or None'''
1626n/a frame = cls.get_selected_frame()
1627n/a
1628n/a while frame:
1629n/a if frame.is_evalframeex():
1630n/a return frame
1631n/a frame = frame.older()
1632n/a
1633n/a # Not found:
1634n/a return None
1635n/a
1636n/a def print_summary(self):
1637n/a if self.is_evalframeex():
1638n/a pyop = self.get_pyop()
1639n/a if pyop:
1640n/a line = pyop.get_truncated_repr(MAX_OUTPUT_LEN)
1641n/a write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line))
1642n/a if not pyop.is_optimized_out():
1643n/a line = pyop.current_line()
1644n/a if line is not None:
1645n/a sys.stdout.write(' %s\n' % line.strip())
1646n/a else:
1647n/a sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index())
1648n/a else:
1649n/a info = self.is_other_python_frame()
1650n/a if info:
1651n/a sys.stdout.write('#%i %s\n' % (self.get_index(), info))
1652n/a else:
1653n/a sys.stdout.write('#%i\n' % self.get_index())
1654n/a
1655n/a def print_traceback(self):
1656n/a if self.is_evalframeex():
1657n/a pyop = self.get_pyop()
1658n/a if pyop:
1659n/a pyop.print_traceback()
1660n/a if not pyop.is_optimized_out():
1661n/a line = pyop.current_line()
1662n/a if line is not None:
1663n/a sys.stdout.write(' %s\n' % line.strip())
1664n/a else:
1665n/a sys.stdout.write(' (unable to read python frame information)\n')
1666n/a else:
1667n/a info = self.is_other_python_frame()
1668n/a if info:
1669n/a sys.stdout.write(' %s\n' % info)
1670n/a else:
1671n/a sys.stdout.write(' (not a python frame)\n')
1672n/a
1673n/aclass PyList(gdb.Command):
1674n/a '''List the current Python source code, if any
1675n/a
1676n/a Use
1677n/a py-list START
1678n/a to list at a different line number within the python source.
1679n/a
1680n/a Use
1681n/a py-list START, END
1682n/a to list a specific range of lines within the python source.
1683n/a '''
1684n/a
1685n/a def __init__(self):
1686n/a gdb.Command.__init__ (self,
1687n/a "py-list",
1688n/a gdb.COMMAND_FILES,
1689n/a gdb.COMPLETE_NONE)
1690n/a
1691n/a
1692n/a def invoke(self, args, from_tty):
1693n/a import re
1694n/a
1695n/a start = None
1696n/a end = None
1697n/a
1698n/a m = re.match(r'\s*(\d+)\s*', args)
1699n/a if m:
1700n/a start = int(m.group(0))
1701n/a end = start + 10
1702n/a
1703n/a m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args)
1704n/a if m:
1705n/a start, end = map(int, m.groups())
1706n/a
1707n/a # py-list requires an actual PyEval_EvalFrameEx frame:
1708n/a frame = Frame.get_selected_bytecode_frame()
1709n/a if not frame:
1710n/a print('Unable to locate gdb frame for python bytecode interpreter')
1711n/a return
1712n/a
1713n/a pyop = frame.get_pyop()
1714n/a if not pyop or pyop.is_optimized_out():
1715n/a print('Unable to read information on python frame')
1716n/a return
1717n/a
1718n/a filename = pyop.filename()
1719n/a lineno = pyop.current_line_num()
1720n/a
1721n/a if start is None:
1722n/a start = lineno - 5
1723n/a end = lineno + 5
1724n/a
1725n/a if start<1:
1726n/a start = 1
1727n/a
1728n/a try:
1729n/a f = open(os_fsencode(filename), 'r')
1730n/a except IOError as err:
1731n/a sys.stdout.write('Unable to open %s: %s\n'
1732n/a % (filename, err))
1733n/a return
1734n/a with f:
1735n/a all_lines = f.readlines()
1736n/a # start and end are 1-based, all_lines is 0-based;
1737n/a # so [start-1:end] as a python slice gives us [start, end] as a
1738n/a # closed interval
1739n/a for i, line in enumerate(all_lines[start-1:end]):
1740n/a linestr = str(i+start)
1741n/a # Highlight current line:
1742n/a if i + start == lineno:
1743n/a linestr = '>' + linestr
1744n/a sys.stdout.write('%4s %s' % (linestr, line))
1745n/a
1746n/a
1747n/a# ...and register the command:
1748n/aPyList()
1749n/a
1750n/adef move_in_stack(move_up):
1751n/a '''Move up or down the stack (for the py-up/py-down command)'''
1752n/a frame = Frame.get_selected_python_frame()
1753n/a if not frame:
1754n/a print('Unable to locate python frame')
1755n/a return
1756n/a
1757n/a while frame:
1758n/a if move_up:
1759n/a iter_frame = frame.older()
1760n/a else:
1761n/a iter_frame = frame.newer()
1762n/a
1763n/a if not iter_frame:
1764n/a break
1765n/a
1766n/a if iter_frame.is_python_frame():
1767n/a # Result:
1768n/a if iter_frame.select():
1769n/a iter_frame.print_summary()
1770n/a return
1771n/a
1772n/a frame = iter_frame
1773n/a
1774n/a if move_up:
1775n/a print('Unable to find an older python frame')
1776n/a else:
1777n/a print('Unable to find a newer python frame')
1778n/a
1779n/aclass PyUp(gdb.Command):
1780n/a 'Select and print the python stack frame that called this one (if any)'
1781n/a def __init__(self):
1782n/a gdb.Command.__init__ (self,
1783n/a "py-up",
1784n/a gdb.COMMAND_STACK,
1785n/a gdb.COMPLETE_NONE)
1786n/a
1787n/a
1788n/a def invoke(self, args, from_tty):
1789n/a move_in_stack(move_up=True)
1790n/a
1791n/aclass PyDown(gdb.Command):
1792n/a 'Select and print the python stack frame called by this one (if any)'
1793n/a def __init__(self):
1794n/a gdb.Command.__init__ (self,
1795n/a "py-down",
1796n/a gdb.COMMAND_STACK,
1797n/a gdb.COMPLETE_NONE)
1798n/a
1799n/a
1800n/a def invoke(self, args, from_tty):
1801n/a move_in_stack(move_up=False)
1802n/a
1803n/a# Not all builds of gdb have gdb.Frame.select
1804n/aif hasattr(gdb.Frame, 'select'):
1805n/a PyUp()
1806n/a PyDown()
1807n/a
1808n/aclass PyBacktraceFull(gdb.Command):
1809n/a 'Display the current python frame and all the frames within its call stack (if any)'
1810n/a def __init__(self):
1811n/a gdb.Command.__init__ (self,
1812n/a "py-bt-full",
1813n/a gdb.COMMAND_STACK,
1814n/a gdb.COMPLETE_NONE)
1815n/a
1816n/a
1817n/a def invoke(self, args, from_tty):
1818n/a frame = Frame.get_selected_python_frame()
1819n/a if not frame:
1820n/a print('Unable to locate python frame')
1821n/a return
1822n/a
1823n/a while frame:
1824n/a if frame.is_python_frame():
1825n/a frame.print_summary()
1826n/a frame = frame.older()
1827n/a
1828n/aPyBacktraceFull()
1829n/a
1830n/aclass PyBacktrace(gdb.Command):
1831n/a 'Display the current python frame and all the frames within its call stack (if any)'
1832n/a def __init__(self):
1833n/a gdb.Command.__init__ (self,
1834n/a "py-bt",
1835n/a gdb.COMMAND_STACK,
1836n/a gdb.COMPLETE_NONE)
1837n/a
1838n/a
1839n/a def invoke(self, args, from_tty):
1840n/a frame = Frame.get_selected_python_frame()
1841n/a if not frame:
1842n/a print('Unable to locate python frame')
1843n/a return
1844n/a
1845n/a sys.stdout.write('Traceback (most recent call first):\n')
1846n/a while frame:
1847n/a if frame.is_python_frame():
1848n/a frame.print_traceback()
1849n/a frame = frame.older()
1850n/a
1851n/aPyBacktrace()
1852n/a
1853n/aclass PyPrint(gdb.Command):
1854n/a 'Look up the given python variable name, and print it'
1855n/a def __init__(self):
1856n/a gdb.Command.__init__ (self,
1857n/a "py-print",
1858n/a gdb.COMMAND_DATA,
1859n/a gdb.COMPLETE_NONE)
1860n/a
1861n/a
1862n/a def invoke(self, args, from_tty):
1863n/a name = str(args)
1864n/a
1865n/a frame = Frame.get_selected_python_frame()
1866n/a if not frame:
1867n/a print('Unable to locate python frame')
1868n/a return
1869n/a
1870n/a pyop_frame = frame.get_pyop()
1871n/a if not pyop_frame:
1872n/a print('Unable to read information on python frame')
1873n/a return
1874n/a
1875n/a pyop_var, scope = pyop_frame.get_var_by_name(name)
1876n/a
1877n/a if pyop_var:
1878n/a print('%s %r = %s'
1879n/a % (scope,
1880n/a name,
1881n/a pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
1882n/a else:
1883n/a print('%r not found' % name)
1884n/a
1885n/aPyPrint()
1886n/a
1887n/aclass PyLocals(gdb.Command):
1888n/a 'Look up the given python variable name, and print it'
1889n/a def __init__(self):
1890n/a gdb.Command.__init__ (self,
1891n/a "py-locals",
1892n/a gdb.COMMAND_DATA,
1893n/a gdb.COMPLETE_NONE)
1894n/a
1895n/a
1896n/a def invoke(self, args, from_tty):
1897n/a name = str(args)
1898n/a
1899n/a frame = Frame.get_selected_python_frame()
1900n/a if not frame:
1901n/a print('Unable to locate python frame')
1902n/a return
1903n/a
1904n/a pyop_frame = frame.get_pyop()
1905n/a if not pyop_frame:
1906n/a print('Unable to read information on python frame')
1907n/a return
1908n/a
1909n/a for pyop_name, pyop_value in pyop_frame.iter_locals():
1910n/a print('%s = %s'
1911n/a % (pyop_name.proxyval(set()),
1912n/a pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
1913n/a
1914n/aPyLocals()