Commit 42fea3e8 authored by Mark Florisson's avatar Mark Florisson

Sort locals and globals

Divide globals into Python globals and C globals (i.e. globals exposed to Python code or "private" globals)
Have cy print and $cy_cvalue() also look in the dict of globals
parent 9084855e
...@@ -7,6 +7,7 @@ from __future__ import with_statement ...@@ -7,6 +7,7 @@ from __future__ import with_statement
import os import os
import sys import sys
import textwrap import textwrap
import operator
import traceback import traceback
import functools import functools
import itertools import itertools
...@@ -128,6 +129,16 @@ def require_running_program(function): ...@@ -128,6 +129,16 @@ def require_running_program(function):
return wrapper return wrapper
def gdb_function_value_to_unicode(function):
@functools.wraps(function)
def wrapper(self, string, *args, **kwargs):
if isinstance(string, gdb.Value):
string = string.string()
return function(self, string, *args, **kwargs)
return wrapper
# Classes that represent the debug information # Classes that represent the debug information
# Don't rename the parameters of these classes, they come directly from the XML # Don't rename the parameters of these classes, they come directly from the XML
...@@ -274,13 +285,6 @@ class CythonBase(object): ...@@ -274,13 +285,6 @@ class CythonBase(object):
return False return False
def print_cython_var_if_initialized(self, varname, max_name_length=None):
try:
self.cy.print_.invoke(varname, True, max_name_length)
except gdb.GdbError:
# variable not initialized yet
pass
@default_selected_gdb_frame(err=False) @default_selected_gdb_frame(err=False)
def print_stackframe(self, frame, index, is_c=False): def print_stackframe(self, frame, index, is_c=False):
""" """
...@@ -338,7 +342,30 @@ class CythonBase(object): ...@@ -338,7 +342,30 @@ class CythonBase(object):
pass pass
selected_frame.select() selected_frame.select()
def get_cython_globals_dict(self):
"""
Get the Cython globals dict where the remote names are turned into
local strings.
"""
m = gdb.parse_and_eval('__pyx_m')
try:
PyModuleObject = gdb.lookup_type('PyModuleObject')
except RuntimeError:
raise gdb.GdbError(textwrap.dedent("""\
Unable to lookup type PyModuleObject, did you compile python
with debugging support (-g)?"""))
m = m.cast(PyModuleObject.pointer())
pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(m['md_dict'])
result = {}
seen = set()
for k, v in pyobject_dict.iteritems():
result[k.proxyval(seen)] = v
return result
class SourceFileDescriptor(object): class SourceFileDescriptor(object):
def __init__(self, filename, lexer, formatter=None): def __init__(self, filename, lexer, formatter=None):
...@@ -946,18 +973,17 @@ class CyPrint(CythonCommand): ...@@ -946,18 +973,17 @@ class CyPrint(CythonCommand):
name = 'cy print' name = 'cy print'
command_class = gdb.COMMAND_DATA command_class = gdb.COMMAND_DATA
@dispatch_on_frame(c_command='print', python_command='py-print')
def invoke(self, name, from_tty, max_name_length=None): def invoke(self, name, from_tty, max_name_length=None):
cname = self.cy.cy_cname.invoke(name) if self.is_python_function():
try: return gdb.execute('py-print ' + name)
value = gdb.parse_and_eval(cname) elif self.is_cython_function():
except RuntimeError, e: value = self.cy.cy_cvalue.invoke(name)
raise gdb.GdbError("Variable %s is not initialized yet." % (name,))
else:
if max_name_length is None: if max_name_length is None:
print '%s = %s' % (name, value) print '%s = %s' % (name, value)
else: else:
print '%-*s = %s' % (max_name_length, name, value) print '%-*s = %s' % (max_name_length, name, value)
else:
gdb.execute('print ' + name)
def complete(self): def complete(self):
if self.is_cython_function(): if self.is_cython_function():
...@@ -967,6 +993,8 @@ class CyPrint(CythonCommand): ...@@ -967,6 +993,8 @@ class CyPrint(CythonCommand):
return [] return []
sortkey = lambda (name, value): name.lower()
class CyLocals(CythonCommand): class CyLocals(CythonCommand):
""" """
List the locals from the current Cython frame. List the locals from the current Cython frame.
...@@ -976,15 +1004,24 @@ class CyLocals(CythonCommand): ...@@ -976,15 +1004,24 @@ class CyLocals(CythonCommand):
command_class = gdb.COMMAND_STACK command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE completer_class = gdb.COMPLETE_NONE
def _print_if_initialized(self, cyvar, max_name_length, prefix=''):
try:
value = gdb.parse_and_eval(cyvar.cname)
except RuntimeError:
# variable not initialized yet
pass
else:
print '%s%-*s = %s' % (prefix, max_name_length, cyvar.name, value)
@dispatch_on_frame(c_command='info locals', python_command='py-locals') @dispatch_on_frame(c_command='info locals', python_command='py-locals')
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
local_cython_vars = self.get_cython_function().locals local_cython_vars = self.get_cython_function().locals
max_name_length = len(max(local_cython_vars, key=len)) max_name_length = len(max(local_cython_vars, key=len))
for varname in local_cython_vars: for name, cyvar in sorted(local_cython_vars.iteritems(), key=sortkey):
self.print_cython_var_if_initialized(varname, max_name_length) self._print_if_initialized(cyvar, max_name_length)
class CyGlobals(CythonCommand):
class CyGlobals(CyLocals):
""" """
List the globals from the current Cython module. List the globals from the current Cython module.
""" """
...@@ -995,39 +1032,30 @@ class CyGlobals(CythonCommand): ...@@ -995,39 +1032,30 @@ class CyGlobals(CythonCommand):
@dispatch_on_frame(c_command='info variables', python_command='py-globals') @dispatch_on_frame(c_command='info variables', python_command='py-globals')
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
m = gdb.parse_and_eval('__pyx_m') global_python_dict = self.get_cython_globals_dict()
module_globals = self.get_cython_function().module.globals
try: max_globals_len = 0
PyModuleObject = gdb.lookup_type('PyModuleObject') max_globals_dict_len = 0
except RuntimeError: if module_globals:
raise gdb.GdbError(textwrap.dedent(""" max_globals_len = len(max(module_globals, key=len))
Unable to lookup type PyModuleObject, did you compile python if global_python_dict:
with debugging support (-g)? max_globals_dict_len = len(max(global_python_dict))
"""))
m = m.cast(PyModuleObject.pointer()) max_name_length = max(max_globals_len, max_globals_dict_len)
pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(m['md_dict'])
module_globals = self.get_cython_function().module.globals
# - 2 for the surrounding quotes
max_name_length = max(len(max(module_globals, key=len)),
len(max(pyobject_dict.iteritems())) - 2)
seen = set() seen = set()
for k, v in pyobject_dict.iteritems(): print 'Python globals:'
# Note: k and v are values in the inferior, they are for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
# libpython.PyObjectPtr objects
k = k.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
# make it look like an actual name (inversion of repr())
k = k[1:-1].decode('string-escape')
v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN) v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
seen.add(k) seen.add(k)
print '%-*s = %s' % (max_name_length, k, v) print ' %-*s = %s' % (max_name_length, k, v)
for varname in seen.symmetric_difference(module_globals): print 'C globals:'
self.print_cython_var_if_initialized(varname, max_name_length) for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
if name not in seen:
self._print_if_initialized(cyvar, max_name_length,
prefix=' ')
# Functions # Functions
...@@ -1043,14 +1071,11 @@ class CyCName(gdb.Function, CythonBase): ...@@ -1043,14 +1071,11 @@ class CyCName(gdb.Function, CythonBase):
""" """
@require_cython_frame @require_cython_frame
@gdb_function_value_to_unicode
def invoke(self, cyname, frame=None): def invoke(self, cyname, frame=None):
frame = frame or gdb.selected_frame() frame = frame or gdb.selected_frame()
cname = None cname = None
if isinstance(cyname, gdb.Value):
# convert to a python string so it supports proper hashing
cyname = cyname.string()
if self.is_cython_function(frame): if self.is_cython_function(frame):
cython_function = self.get_cython_function(frame) cython_function = self.get_cython_function(frame)
if cyname in cython_function.locals: if cyname in cython_function.locals:
...@@ -1077,10 +1102,22 @@ class CyCValue(CyCName): ...@@ -1077,10 +1102,22 @@ class CyCValue(CyCName):
""" """
@require_cython_frame @require_cython_frame
@gdb_function_value_to_unicode
def invoke(self, cyname, frame=None): def invoke(self, cyname, frame=None):
cname = super(CyCValue, self).invoke(cyname, frame=frame) cname = super(CyCValue, self).invoke(cyname, frame=frame)
return gdb.parse_and_eval(cname) try:
return gdb.parse_and_eval(cname)
except RuntimeError:
# variable exists but may not have been initialized yet, or may be
# in the globals dict of the Cython module
if cyname in self.get_cython_function().module.globals:
# look in the global dict
d = self.get_cython_globals_dict()
if cyname in d:
return d[cyname]._gdbval
# print cyname, self.get_cython_function().module.globals, '\n', self.get_cython_globals_dict()
raise gdb.GdbError("Variable %s not initialized yet." % cyname)
class CyLine(gdb.Function, CythonBase): class CyLine(gdb.Function, CythonBase):
""" """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment