diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 93f1c8e..2af5800 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -47,7 +47,8 @@ class DebuggerTests(unittest.TestCase): return out, err def get_stack_trace(self, source, breakpoint='PyObject_Print', - commands_after_breakpoint=None): + commands_after_breakpoint=None, + import_site=False): ''' Run 'python -c SOURCE' under gdb with a breakpoint. @@ -84,8 +85,13 @@ class DebuggerTests(unittest.TestCase): args = ["gdb", "--batch"] args += ['--eval-command=%s' % cmd for cmd in commands] args += ["--args", - sys.executable, "-S", "-c", source] - # -S suppresses the default 'import site' + sys.executable] + + if not import_site: + # -S suppresses the default 'import site' + args += ["-S"] + + args += ["-c", source] # print args @@ -101,7 +107,8 @@ class DebuggerTests(unittest.TestCase): return out def get_gdb_repr(self, source, - commands_after_breakpoint=None): + commands_after_breakpoint=None, + import_site=False): # Given an input python source representation of data, # run "python -c'print DATA'" under gdb with a breakpoint on # PyObject_Print and scrape out gdb's representation of the "op" @@ -110,7 +117,8 @@ class DebuggerTests(unittest.TestCase): # For a nested structure, the first time we hit the breakpoint will # give us the top-level structure gdb_output = self.get_stack_trace(source, 'PyObject_Print', - commands_after_breakpoint) + commands_after_breakpoint, + import_site) m = re.match('.*#0 PyObject_Print \(op\=(.*?), fp=.*\).*', gdb_output, re.DOTALL) #print m.groups() @@ -248,6 +256,26 @@ print foo''') self.assertSane('print 42', 'set op->ob_type->tp_name=0xDEADBEEF') + def test_NULL_instance_dict(self): + self.assertSane(''' +class Foo: + pass +foo = Foo() +foo.an_int = 42 +print foo''', + 'set ((PyInstanceObject*)op)->in_dict = 0', + exp_type='Foo') + + def test_builtins_help(self): + # Ensure that the new-style class _Helper in site.py can be handled + # (this was the issue causing tracebacks in + # http://bugs.python.org/issue8032#msg100537 ) + + gdb_repr, gdb_output = self.get_gdb_repr('print __builtins__.help', import_site=True) + m = re.match(r'<_Helper at remote 0x[0-9a-f]+>', gdb_repr) + self.assertTrue(m, + msg='Unexpected rendering %r' % gdb_repr) + # TODO: # frames diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 15a05a6..1ef0e69 100644 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1,11 +1,4 @@ #!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright © 2010 David Hugh Malcolm -# -# This software is licensed to you under the same terms as Python itself -# -# Author: Dave Malcolm ''' From gdb 7 onwards, gdb's build can be configured --with-python, allowing gdb to be extended with Python code e.g. for library-specific data visualizations, @@ -267,10 +260,14 @@ class InstanceProxy(object): self.address = address def __repr__(self): - kwargs = ', '.join(["%s=%r" % (arg, val) - for arg, val in self.attrdict.iteritems()]) - return '<%s(%s) at remote 0x%x>' % (self.cl_name, - kwargs, self.address) + if isinstance(self.attrdict, dict): + kwargs = ', '.join(["%s=%r" % (arg, val) + for arg, val in self.attrdict.iteritems()]) + return '<%s(%s) at remote 0x%x>' % (self.cl_name, + kwargs, self.address) + else: + return '<%s at remote 0x%x>' % (self.cl_name, + self.address) def _PyObject_VAR_SIZE(typeobj, nitems):