From 150a0120ecbbf16091ddcbe1d0bd752619abc352 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Sat, 27 Feb 2010 00:40:21 -0500 Subject: Improve layout --- test_gdb.py | 83 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 36 deletions(-) (limited to 'test_gdb.py') diff --git a/test_gdb.py b/test_gdb.py index e9ce82a..d7cd237 100644 --- a/test_gdb.py +++ b/test_gdb.py @@ -20,23 +20,26 @@ except OSError: raise TestSkipped("Couldn't find gdb on the path") gdb_version_number = re.search(r"^GNU gdb [^\d]*(\d+)\.", gdb_version) if int(gdb_version_number.group(1)) < 7: - raise TestSkipped("gdb versions before 7.0 didn't support python embedding." + raise TestSkipped("gdb versions before 7.0 didn't support python embedding" " Saw:\n" + gdb_version) # Verify that "gdb" was built with the embedded python support enabled: -p = subprocess.Popen(["gdb", "--batch", - "--eval-command=python import sys; print sys.version_info"], +cmd = "--eval-command=python import sys; print sys.version_info" +p = subprocess.Popen(["gdb", "--batch", cmd], stdout=subprocess.PIPE) gdbpy_version, _ = p.communicate() if gdbpy_version == '': raise TestSkipped("gdb not built with embedded python support") + class DebuggerTests(unittest.TestCase): """Test that the debugger can debug Python.""" def run_gdb(self, *args): - """Runs gdb with the command line given by *args. Returns its stdout, stderr + """Runs gdb with the command line given by *args. + + Returns its stdout, stderr """ out, err = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -106,8 +109,10 @@ 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) - m = re.match('.*#0 PyObject_Print \(op\=(.*?), fp=.*\).*', gdb_output, re.DOTALL) + gdb_output = self.get_stack_trace(source, 'PyObject_Print', + commands_after_breakpoint) + m = re.match('.*#0 PyObject_Print \(op\=(.*?), fp=.*\).*', + gdb_output, re.DOTALL) #print m.groups() return m.group(1), gdb_output @@ -118,9 +123,10 @@ class DebuggerTests(unittest.TestCase): def assertGdbRepr(self, val, commands_after_breakpoint=None): # Ensure that gdb's rendering of the value in a debugged process # matches repr(value) in this process: - gdb_repr, gdb_output = self.get_gdb_repr('print ' + repr(val), commands_after_breakpoint) + gdb_repr, gdb_output = self.get_gdb_repr('print ' + repr(val), + commands_after_breakpoint) self.assertEquals(gdb_repr, repr(val), gdb_output) - + def test_int(self): self.assertGdbRepr(42) self.assertGdbRepr(0) @@ -141,7 +147,7 @@ class DebuggerTests(unittest.TestCase): def test_dicts(self): self.assertGdbRepr({}) - self.assertGdbRepr({'foo':'bar'}) + self.assertGdbRepr({'foo': 'bar'}) def test_lists(self): self.assertGdbRepr([]) @@ -152,20 +158,12 @@ class DebuggerTests(unittest.TestCase): self.assertGdbRepr('And now for something hopefully the same') def test_tuples(self): - self.assertGdbRepr( tuple() ) - self.assertGdbRepr( (1,) ) + self.assertGdbRepr(tuple()) + self.assertGdbRepr((1,)) def test_unicode(self): - self.assertGdbRepr( u'hello world', ) - self.assertGdbRepr( u'\u2620') - - def assert_is_failsafe_repr(self, gdb_repr, exp_type='unknown'): - '''Verify that the given gdb_repr string is the expected failsafe - representation for when there's corrupt data within the inferior - process''' - self.assertTrue(re.match('<%s at remote 0x[0-9a-f]+>' % exp_type, - gdb_repr), - 'Unexpected gdb representation: %r' % gdb_repr) + self.assertGdbRepr(u'hello world') + self.assertGdbRepr(u'\u2620') def test_classic_class(self): gdb_repr, gdb_output = self.get_gdb_repr(''' @@ -174,34 +172,47 @@ class Foo: foo = Foo(); foo.an_int = 42; print foo''') - # FIXME: is there an "assertMatches"; should there be? + # FIXME: is there an "assertMatches"; should there be? m = re.match(r'', gdb_repr) - self.assertTrue(m, msg='Unexpected classic-class rendering %r' % gdb_repr) + self.assertTrue(m, + msg='Unexpected classic-class rendering %r' % gdb_repr) + + def assertSane(self, source, corruption, exp_type='unknown'): + '''Run Python under gdb, corrupting variables in the inferior process + immediately before taking a backtrace. + + Verify that the variable's representation is the expected failsafe + representation''' + gdb_repr, gdb_output = \ + self.get_gdb_repr(source, + commands_after_breakpoint=[corruption]) + self.assertTrue(re.match('<%s at remote 0x[0-9a-f]+>' % exp_type, + gdb_repr), + 'Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) def test_NULL_ob_type(self): - gdb_repr, gdb_output = self.get_gdb_repr('print 42', - commands_after_breakpoint=['set op->ob_type=0']) - self.assert_is_failsafe_repr(gdb_repr) + self.assertSane('print 42', + 'set op->ob_type=0') def test_corrupt_ob_type(self): - gdb_repr, gdb_output = self.get_gdb_repr('print "this string will have its ob_type corrupted"', - commands_after_breakpoint=['set op->ob_type=0xDEADBEEF']) - self.assert_is_failsafe_repr(gdb_repr) + self.assertSane('print 42', + 'set op->ob_type=0xDEADBEEF') def test_corrupt_tp_flags(self): - gdb_repr, gdb_output = self.get_gdb_repr('print 42', - commands_after_breakpoint=['set op->ob_type->tp_flags=0x0']) - self.assert_is_failsafe_repr(gdb_repr, exp_type='int') + self.assertSane('print 42', + 'set op->ob_type->tp_flags=0x0', + exp_type='int') def test_corrupt_tp_name(self): - gdb_repr, gdb_output = self.get_gdb_repr('print 42', - commands_after_breakpoint=['set op->ob_type->tp_name=0xDEADBEEF']) - self.assert_is_failsafe_repr(gdb_repr) - + self.assertSane('print 42', + 'set op->ob_type->tp_name=0xDEADBEEF') + # TODO: # new-style classes # frames + def test_main(): #run_unittest(DebuggerTests) unittest.main() -- cgit