Index: Tools/gdb/libpython.py =================================================================== --- Tools/gdb/libpython.py (revision 80008) +++ Tools/gdb/libpython.py (working copy) @@ -19,9 +19,10 @@ In particular, given a gdb.Value corresponding to a PyObject* in the inferior process, we can generate a "proxy value" within the gdb process. For example, given a PyObject* in the inferior process that is in fact a PyListObject* -holding three PyObject* that turn out to be PyStringObject* instances, we can -generate a proxy value within the gdb process that is a list of strings: - ["foo", "bar", "baz"] +holding three PyObject* that turn out to be PyBytesObject* instances, we can +generate a proxy value within the gdb process that is a list of bytes +instances: + [b"foo", b"bar", b"baz"] Doing so can be expensive for complicated graphs of objects, and could take some time, so we also have a "write_repr" method that writes a representation @@ -57,7 +58,7 @@ Py_TPFLAGS_LONG_SUBCLASS = (1L << 24) Py_TPFLAGS_LIST_SUBCLASS = (1L << 25) Py_TPFLAGS_TUPLE_SUBCLASS = (1L << 26) -Py_TPFLAGS_STRING_SUBCLASS = (1L << 27) +Py_TPFLAGS_BYTES_SUBCLASS = (1L << 27) Py_TPFLAGS_UNICODE_SUBCLASS = (1L << 28) Py_TPFLAGS_DICT_SUBCLASS = (1L << 29) Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30) @@ -108,7 +109,7 @@ class PyObjectPtr(object): """ Class wrapping a gdb.Value that's a either a (PyObject*) within the - inferior process, or some subclass pointer e.g. (PyStringObject*) + inferior process, or some subclass pointer e.g. (PyBytesObject*) There will be a subclass for every refined PyObject type that we care about. @@ -148,12 +149,8 @@ return pyo_ptr.dereference()[name] if name == 'ob_size': - try: - # Python 2: - return self._gdbval.dereference()[name] - except RuntimeError: - # Python 3: - return self._gdbval.dereference()['ob_base'][name] + pyo_ptr = self._gdbval.cast(PyVarObjectPtr.get_gdb_type()) + return pyo_ptr.dereference()[name] # General case: look it up inside the object: return self._gdbval.dereference()[name] @@ -318,8 +315,8 @@ return PyListObjectPtr if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS: return PyTupleObjectPtr - if tp_flags & Py_TPFLAGS_STRING_SUBCLASS: - return PyStringObjectPtr + if tp_flags & Py_TPFLAGS_BYTES_SUBCLASS: + return PyBytesObjectPtr if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS: return PyUnicodeObjectPtr if tp_flags & Py_TPFLAGS_DICT_SUBCLASS: @@ -355,6 +352,8 @@ def as_address(self): return long(self._gdbval) +class PyVarObjectPtr(PyObjectPtr): + _typename = 'PyVarObject' class ProxyAlreadyVisited(object): ''' @@ -515,20 +514,6 @@ out.write(self.safe_tp_name()) self.write_field_repr('args', out, visited) -class PyBoolObjectPtr(PyObjectPtr): - """ - Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two - instances (Py_True/Py_False) within the process being debugged. - """ - _typename = 'PyBoolObject' - - def proxyval(self, visited): - if int_from_int(self.field('ob_ival')): - return True - else: - return False - - class PyClassObjectPtr(PyObjectPtr): """ Class wrapping a gdb.Value that's a PyClassObject* i.e. a @@ -691,13 +676,6 @@ _write_instance_repr(out, visited, cl_name, pyop_in_dict, self.as_address()) -class PyIntObjectPtr(PyObjectPtr): - _typename = 'PyIntObject' - - def proxyval(self, visited): - result = int_from_int(self.field('ob_ival')) - return result - class PyListObjectPtr(PyObjectPtr): _typename = 'PyListObject' @@ -770,6 +748,16 @@ result = -result return result +class PyBoolObjectPtr(PyLongObjectPtr): + """ + Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two + instances (Py_True/Py_False) within the process being debugged. + """ + def proxyval(self, visited): + if PyLongObjectPtr.proxyval(self, visited): + return True + else: + return False class PyNoneStructPtr(PyObjectPtr): """ @@ -894,9 +882,9 @@ return out.write('Frame 0x%x, for file %s, line %i, in %s (' % (self.as_address(), - self.co_filename, + self.co_filename.proxyval(visited), self.current_line_num(), - self.co_name)) + self.co_name.proxyval(visited))) first = True for pyop_name, pyop_value in self.iter_locals(): if not first: @@ -958,8 +946,8 @@ out.write('])') -class PyStringObjectPtr(PyObjectPtr): - _typename = 'PyStringObject' +class PyBytesObjectPtr(PyObjectPtr): + _typename = 'PyBytesObject' def __str__(self): field_ob_size = self.field('ob_size') @@ -1065,7 +1053,7 @@ if type.code == gdb.TYPE_CODE_PTR: type = type.target().unqualified() t = str(type) - if t in ("PyObject", "PyFrameObject"): + if t in ("PyObject", "PyFrameObject", "PyUnicodeObject"): return PyObjectPtrPrinter(gdbval) """ Index: Lib/test/test_gdb.py =================================================================== --- Lib/test/test_gdb.py (revision 80008) +++ Lib/test/test_gdb.py (working copy) @@ -9,7 +9,7 @@ import sys import unittest -from test.support import run_unittest +from test.support import run_unittest, findfile try: gdb_version, _ = subprocess.Popen(["gdb", "--version"], @@ -44,10 +44,10 @@ out, err = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ).communicate() - return out, err + return out.decode('utf-8'), err.decode('utf-8') def get_stack_trace(self, source=None, script=None, - breakpoint='PyObject_Print', + breakpoint='builtin_id', cmds_after_breakpoint=None, import_site=False): ''' @@ -65,7 +65,7 @@ # error, which typically happens python is dynamically linked (the # breakpoints of interest are to be found in the shared library) # When this happens, we still get: - # Function "PyObject_Print" not defined. + # Function "builtin_id" not defined. # emitted to stderr each time, alas. # Initially I had "--eval-command=continue" here, but removed it to @@ -116,19 +116,21 @@ cmds_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" - # parameter, and verify that the gdb displays the same string + # run "python -c'id(DATA)'" under gdb with a breakpoint on the C + # implementation of "id" (i.e. the 'builtin_id' function), and scrape + # out gdb's representation of the "op". # + # Verify that the gdb displays the expected string + # # 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, breakpoint='PyObject_Print', + gdb_output = self.get_stack_trace(source, breakpoint='builtin_id', cmds_after_breakpoint=cmds_after_breakpoint, import_site=import_site) # gdb can insert additional '\n' and space characters in various places # in its output, depending on the width of the terminal it's connected # to (using its "wrap_here" function) - m = re.match('.*#0\s+PyObject_Print\s+\(\s*op\=\s*(.*?),\s+fp=.*\).*', + m = re.match('.*#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)\)\s+at\s+Python/bltinmodule.c.*', gdb_output, re.DOTALL) if not m: self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) @@ -141,36 +143,38 @@ def assertMultilineMatches(self, actual, pattern): m = re.match(pattern, actual, re.DOTALL) - self.assert_(m, - msg='%r did not match %r' % (actual, pattern)) + if not m: + self.fail(msg='%r did not match %r' % (actual, pattern)) + def get_sample_script(self): + return findfile('gdb_sample.py') + class PrettyPrintTests(DebuggerTests): def test_getting_backtrace(self): - gdb_output = self.get_stack_trace('print 42') - self.assertTrue('PyObject_Print' in gdb_output) + gdb_output = self.get_stack_trace('id(42)') + self.assertTrue('builtin_id' in gdb_output) - def assertGdbRepr(self, val, cmds_after_breakpoint=None): + def assertGdbRepr(self, val, exp_repr=None, cmds_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), + gdb_repr, gdb_output = self.get_gdb_repr('id(%s)' % repr(val), cmds_after_breakpoint) - self.assertEquals(gdb_repr, repr(val), gdb_output) + if not exp_repr: + exp_repr = repr(val) + self.assertEquals(gdb_repr, exp_repr, + ('%r did not equal expected %r; full output was:\n%s' + % (gdb_repr, exp_repr, gdb_output))) def test_int(self): - 'Verify the pretty-printing of various "int" values' - self.assertGdbRepr(42) - self.assertGdbRepr(0) - self.assertGdbRepr(-7) - self.assertGdbRepr(sys.maxint) - self.assertGdbRepr(-sys.maxint) + 'Verify the pretty-printing of various "int"/long values' + self.assertGdbRepr(42, exp_repr='42L') + self.assertGdbRepr(0, exp_repr='0L') + self.assertGdbRepr(-7, exp_repr='-7L') + self.assertGdbRepr(1000000000000, + exp_repr="1000000000000L") + self.assertGdbRepr(-1000000000000000, + exp_repr="-1000000000000000L") - def test_long(self): - 'Verify the pretty-printing of various "long" values' - self.assertGdbRepr(0) - self.assertGdbRepr(1000000000000) - self.assertGdbRepr(-1) - self.assertGdbRepr(-1000000000000000) - def test_singletons(self): 'Verify the pretty-printing of True, False and None' self.assertGdbRepr(True) @@ -180,119 +184,115 @@ def test_dicts(self): 'Verify the pretty-printing of dictionaries' self.assertGdbRepr({}) - self.assertGdbRepr({'foo': 'bar'}) - self.assertGdbRepr({'foo': 'bar', 'douglas':42}) + self.assertGdbRepr({'foo': 'bar'}, + exp_repr="{u'foo': u'bar'}") + self.assertGdbRepr({'foo': 'bar', 'douglas':42}, + exp_repr="{u'foo': u'bar', u'douglas': 42L}") def test_lists(self): 'Verify the pretty-printing of lists' self.assertGdbRepr([]) - self.assertGdbRepr(range(5)) + self.assertGdbRepr(list(range(5)), + exp_repr='[0L, 1L, 2L, 3L, 4L]') def test_strings(self): - 'Verify the pretty-printing of strings' - self.assertGdbRepr('') - self.assertGdbRepr('And now for something hopefully the same') - self.assertGdbRepr('string with embedded NUL here \0 and then some more text') - self.assertGdbRepr('this is byte 255:\xff and byte 128:\x80') + 'Verify the pretty-printing of unicode strings' + self.assertGdbRepr('', exp_repr="u''") + self.assertGdbRepr('And now for something hopefully the same', + exp_repr="u'And now for something hopefully the same'") + self.assertGdbRepr('string with embedded NUL here \0 and then some more text', + "u'string with embedded NUL here \\x00 and then some more text'") + self.assertGdbRepr('this is byte 255:\xff and byte 128:\x80', + "u'this is byte 255:\\xff and byte 128:\\x80'") - def test_tuples(self): - 'Verify the pretty-printing of tuples' - self.assertGdbRepr(tuple()) - self.assertGdbRepr((1,)) - self.assertGdbRepr(('foo', 'bar', 'baz')) - - def test_unicode(self): - 'Verify the pretty-printing of unicode values' - # Test the empty unicode string: - self.assertGdbRepr('') - - self.assertGdbRepr('hello world') - # Test printing a single character: # U+2620 SKULL AND CROSSBONES - self.assertGdbRepr('\u2620') + self.assertGdbRepr('\u2620', + "u'\\u2620'") # Test printing a Japanese unicode string # (I believe this reads "mojibake", using 3 characters from the CJK # Unified Ideographs area, followed by U+3051 HIRAGANA LETTER KE) - self.assertGdbRepr('\u6587\u5b57\u5316\u3051') + self.assertGdbRepr('\u6587\u5b57\u5316\u3051', + "u'\\u6587\\u5b57\\u5316\\u3051'") # Test a character outside the BMP: # U+1D121 MUSICAL SYMBOL C CLEF # This is: # UTF-8: 0xF0 0x9D 0x84 0xA1 # UTF-16: 0xD834 0xDD21 - try: - # This will only work on wide-unicode builds: - self.assertGdbRepr(chr(0x1D121)) - except ValueError as e: - if e.message != 'chr() arg not in range(0x10000) (narrow Python build)': - raise e + if sys.maxunicode == 0x10FFFF: + # wide unicode: + self.assertGdbRepr(chr(0x1D121), + "u'\\U0001d121'") + else: + # narrow unicode: + self.assertGdbRepr(chr(0x1D121), + "u'\\ud834\\udd21'") + def test_tuples(self): + 'Verify the pretty-printing of tuples' + self.assertGdbRepr(tuple()) + self.assertGdbRepr((1,), '(1L,)') + self.assertGdbRepr(('foo', 'bar', 'baz'), + "(u'foo', u'bar', u'baz')") + def test_sets(self): 'Verify the pretty-printing of sets' - self.assertGdbRepr(set()) - self.assertGdbRepr(set(['a', 'b'])) - self.assertGdbRepr(set([4, 5, 6])) + self.assertGdbRepr(set(), + exp_repr='set([])') + self.assertGdbRepr(set(['a', 'b']), + exp_repr="set([u'a', u'b'])") + self.assertGdbRepr(set([4, 5, 6]), + exp_repr="set([4L, 5L, 6L])") # Ensure that we handled sets containing the "dummy" key value, # which happens on deletion: gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) s.pop() -print s''') - self.assertEquals(gdb_repr, "set(['b'])") +id(s)''') + self.assertEquals(gdb_repr, "set([u'b'])") def test_frozensets(self): 'Verify the pretty-printing of frozensets' - self.assertGdbRepr(frozenset()) - self.assertGdbRepr(frozenset(['a', 'b'])) - self.assertGdbRepr(frozenset([4, 5, 6])) + self.assertGdbRepr(frozenset(), + exp_repr='frozenset([])') + self.assertGdbRepr(frozenset(['a', 'b']), + exp_repr="frozenset([u'a', u'b'])") + self.assertGdbRepr(frozenset([4, 5, 6]), + exp_repr="frozenset([4L, 5L, 6L])") def test_exceptions(self): # Test a RuntimeError gdb_repr, gdb_output = self.get_gdb_repr(''' try: raise RuntimeError("I am an error") -except RuntimeError, e: - print e +except RuntimeError as e: + id(e) ''') self.assertEquals(gdb_repr, - "exceptions.RuntimeError('I am an error',)") + "RuntimeError(u'I am an error',)") # Test division by zero: gdb_repr, gdb_output = self.get_gdb_repr(''' try: a = 1 / 0 -except ZeroDivisionError, e: - print e +except ZeroDivisionError as e: + id(e) ''') self.assertEquals(gdb_repr, - "exceptions.ZeroDivisionError('integer division or modulo by zero',)") + "ZeroDivisionError(u'division by zero',)") - def test_classic_class(self): - 'Verify the pretty-printing of classic class instances' - gdb_repr, gdb_output = self.get_gdb_repr(''' -class Foo: - pass -foo = Foo() -foo.an_int = 42 -print foo''') - m = re.match(r'', gdb_repr) - self.assertTrue(m, - msg='Unexpected classic-class rendering %r' % gdb_repr) - def test_modern_class(self): 'Verify the pretty-printing of new-style class instances' gdb_repr, gdb_output = self.get_gdb_repr(''' -class Foo(object): +class Foo: pass foo = Foo() foo.an_int = 42 -print foo''') - m = re.match(r'', gdb_repr) - self.assertTrue(m, - msg='Unexpected new-style class rendering %r' % gdb_repr) +id(foo)''') + self.assertMultilineMatches(gdb_repr, r'') def test_subclassing_list(self): 'Verify the pretty-printing of an instance of a list subclass' @@ -302,8 +302,8 @@ foo = Foo() foo += [1, 2, 3] foo.an_int = 42 -print foo''') - m = re.match(r'', gdb_repr) +id(foo)''') + m = re.match(r'', gdb_repr) self.assertTrue(m, msg='Unexpected new-style class rendering %r' % gdb_repr) @@ -316,12 +316,12 @@ pass foo = Foo((1, 2, 3)) foo.an_int = 42 -print foo''') - m = re.match(r'', gdb_repr) +id(foo)''') + m = re.match(r'', gdb_repr) self.assertTrue(m, msg='Unexpected new-style class rendering %r' % gdb_repr) - def assertSane(self, source, corruption, exp_type='unknown'): + def assertSane(self, source, corruption, exprepr=None): '''Run Python under gdb, corrupting variables in the inferior process immediately before taking a backtrace. @@ -335,16 +335,26 @@ gdb_repr, gdb_output = \ self.get_gdb_repr(source, cmds_after_breakpoint=cmds_after_breakpoint) - 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)) + if exprepr: + if gdb_repr == exprepr: + # gdb managed to print the value in spite of the corruption; + # this is good (see http://bugs.python.org/issue8330) + return + # Match anything for the type name; 0xDEADBEEF could point to + # something arbitrary (see http://bugs.python.org/issue8330) + pattern = '<.* at remote 0x[0-9a-f]+>' + + m = re.match(pattern, gdb_repr) + if not m: + self.fail('Unexpected gdb representation: %r\n%s' % \ + (gdb_repr, gdb_output)) + def test_NULL_ptr(self): 'Ensure that a NULL PyObject* is handled gracefully' gdb_repr, gdb_output = ( - self.get_gdb_repr('print 42', - cmds_after_breakpoint=['set variable op=0', + self.get_gdb_repr('id(42)', + cmds_after_breakpoint=['set variable v=0', 'backtrace']) ) @@ -352,42 +362,33 @@ def test_NULL_ob_type(self): 'Ensure that a PyObject* with NULL ob_type is handled gracefully' - self.assertSane('print 42', - 'set op->ob_type=0') + self.assertSane('id(42)', + 'set v->ob_type=0') def test_corrupt_ob_type(self): 'Ensure that a PyObject* with a corrupt ob_type is handled gracefully' - self.assertSane('print 42', - 'set op->ob_type=0xDEADBEEF') + self.assertSane('id(42)', + 'set v->ob_type=0xDEADBEEF', + exprepr="42L") def test_corrupt_tp_flags(self): 'Ensure that a PyObject* with a type with corrupt tp_flags is handled' - self.assertSane('print 42', - 'set op->ob_type->tp_flags=0x0', - exp_type='int') + self.assertSane('id(42)', + 'set v->ob_type->tp_flags=0x0', + exprepr="42L") def test_corrupt_tp_name(self): 'Ensure that a PyObject* with a type with corrupt tp_name is handled' - self.assertSane('print 42', - 'set op->ob_type->tp_name=0xDEADBEEF') + self.assertSane('id(42)', + 'set v->ob_type->tp_name=0xDEADBEEF', + exprepr="42L") - def test_NULL_instance_dict(self): - 'Ensure that a PyInstanceObject with with a NULL in_dict is handled' - 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) + gdb_repr, gdb_output = self.get_gdb_repr('id(__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) @@ -396,22 +397,22 @@ '''Ensure that a reference loop involving a list doesn't lead proxyval into an infinite loop:''' gdb_repr, gdb_output = \ - self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; print a") + self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; id(a)") - self.assertEquals(gdb_repr, '[3, 4, 5, [...]]') + self.assertEquals(gdb_repr, '[3L, 4L, 5L, [...]]') gdb_repr, gdb_output = \ - self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; print a") + self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)") - self.assertEquals(gdb_repr, '[3, 4, 5, [[...]]]') + self.assertEquals(gdb_repr, '[3L, 4L, 5L, [[...]]]') def test_selfreferential_dict(self): '''Ensure that a reference loop involving a dict doesn't lead proxyval into an infinite loop:''' gdb_repr, gdb_output = \ - self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; print a") + self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)") - self.assertEquals(gdb_repr, "{'foo': {'bar': {...}}}") + self.assertEquals(gdb_repr, "{u'foo': {u'bar': {...}}}") def test_selfreferential_old_style_instance(self): gdb_repr, gdb_output = \ @@ -420,7 +421,7 @@ pass foo = Foo() foo.an_attr = foo -print foo''') +id(foo)''') self.assertTrue(re.match('\) at remote 0x[0-9a-f]+>', gdb_repr), 'Unexpected gdb representation: %r\n%s' % \ @@ -433,7 +434,7 @@ pass foo = Foo() foo.an_attr = foo -print foo''') +id(foo)''') self.assertTrue(re.match('\) at remote 0x[0-9a-f]+>', gdb_repr), 'Unexpected gdb representation: %r\n%s' % \ @@ -447,7 +448,7 @@ b = Foo() a.an_attr = b b.an_attr = a -print a''') +id(a)''') self.assertTrue(re.match('\) at remote 0x[0-9a-f]+>\) at remote 0x[0-9a-f]+>', gdb_repr), 'Unexpected gdb representation: %r\n%s' % \ @@ -455,39 +456,34 @@ def test_truncation(self): 'Verify that very long output is truncated' - gdb_repr, gdb_output = self.get_gdb_repr('print range(1000)') + gdb_repr, gdb_output = self.get_gdb_repr('id(list(range(1000)))') self.assertEquals(gdb_repr, - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " - "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, " - "27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, " - "40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, " - "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, " - "66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, " - "79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, " - "92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, " - "104, 105, 106, 107, 108, 109, 110, 111, 112, 113, " - "114, 115, 116, 117, 118, 119, 120, 121, 122, 123, " - "124, 125, 126, 127, 128, 129, 130, 131, 132, 133, " - "134, 135, 136, 137, 138, 139, 140, 141, 142, 143, " - "144, 145, 146, 147, 148, 149, 150, 151, 152, 153, " - "154, 155, 156, 157, 158, 159, 160, 161, 162, 163, " - "164, 165, 166, 167, 168, 169, 170, 171, 172, 173, " - "174, 175, 176, 177, 178, 179, 180, 181, 182, 183, " - "184, 185, 186, 187, 188, 189, 190, 191, 192, 193, " - "194, 195, 196, 197, 198, 199, 200, 201, 202, 203, " - "204, 205, 206, 207, 208, 209, 210, 211, 212, 213, " - "214, 215, 216, 217, 218, 219, 220, 221, 222, 223, " - "224, 225, 226...(truncated)") + "[0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, " + "11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, " + "21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, " + "31L, 32L, 33L, 34L, 35L, 36L, 37L, 38L, 39L, 40L, " + "41L, 42L, 43L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, " + "51L, 52L, 53L, 54L, 55L, 56L, 57L, 58L, 59L, 60L, " + "61L, 62L, 63L, 64L, 65L, 66L, 67L, 68L, 69L, 70L, " + "71L, 72L, 73L, 74L, 75L, 76L, 77L, 78L, 79L, 80L, " + "81L, 82L, 83L, 84L, 85L, 86L, 87L, 88L, 89L, 90L, " + "91L, 92L, 93L, 94L, 95L, 96L, 97L, 98L, 99L, 100L, " + "101L, 102L, 103L, " + "104L, 105L, 106L, 107L, 108L, 109L, 110L, 111L, 112L, 113L, " + "114L, 115L, 116L, 117L, 118L, 119L, 120L, 121L, 122L, 123L, " + "124L, 125L, 126L, 127L, 128L, 129L, 130L, 131L, 132L, 133L, " + "134L, 135L, 136L, 137L, 138L, 139L, 140L, 141L, 142L, 143L, " + "144L, 145L, 146L, 147L, 148L, 149L, 150L, 151L, 152L, 153L, " + "154L, 155L, 156L, 157L, 158L, 159L, 160L, 161L, 162L, 163L, " + "164L, 165L, 166L, 167L, 168L, 169L, 170L, 171L, 172L, 173L, " + "174L, 175L, 176L, 177L, 178L, 179L, 180L, 181L, 182L, 183L, " + "184L, 185L, 186L, 187L, 188L,...(truncated)") self.assertEquals(len(gdb_repr), 1024 + len('...(truncated)')) - def test_builtin_function(self): - gdb_repr, gdb_output = self.get_gdb_repr('print len') - self.assertEquals(gdb_repr, '') - def test_builtin_method(self): - gdb_repr, gdb_output = self.get_gdb_repr('import sys; print sys.stdout.readlines') - self.assertTrue(re.match('', + gdb_repr, gdb_output = self.get_gdb_repr('import sys; id(sys.stdout.readlines)') + self.assertTrue(re.match('', gdb_repr), 'Unexpected gdb representation: %r\n%s' % \ (gdb_repr, gdb_output)) @@ -498,11 +494,11 @@ pass foo(3, 4, 5) -print foo.__code__''', - breakpoint='PyObject_Print', - cmds_after_breakpoint=['print (PyFrameObject*)(((PyCodeObject*)op)->co_zombieframe)'] +id(foo.__code__)''', + breakpoint='builtin_id', + cmds_after_breakpoint=['print (PyFrameObject*)(((PyCodeObject*)v)->co_zombieframe)'] ) - self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x[0-9a-f]+, for file , line 3, in foo \(\)\s+.*', + self.assertTrue(re.match('.*\s+\$1 =\s+Frame 0x[0-9a-f]+, for file , line 3, in foo \(\)\s+.*', gdb_output, re.DOTALL), 'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output)) @@ -513,136 +509,130 @@ def test_basic_command(self): 'Verify that the "py-list" command works' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-list']) - self.assertListing(''' - 5 - 6 def bar(a, b, c): - 7 baz(a, b, c) - 8 - 9 def baz(*args): - >10 print(42) - 11 - 12 foo(1, 2, 3) -''', - bt) + self.assertListing(' 5 \n' + ' 6 def bar(a, b, c):\n' + ' 7 baz(a, b, c)\n' + ' 8 \n' + ' 9 def baz(*args):\n' + ' >10 id(42)\n' + ' 11 \n' + ' 12 foo(1, 2, 3)\n', + bt) def test_one_abs_arg(self): 'Verify the "py-list" command with one absolute argument' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-list 9']) - self.assertListing(''' - 9 def baz(*args): - >10 print(42) - 11 - 12 foo(1, 2, 3) -''', - bt) + self.assertListing(' 9 def baz(*args):\n' + ' >10 id(42)\n' + ' 11 \n' + ' 12 foo(1, 2, 3)\n', + bt) def test_two_abs_args(self): 'Verify the "py-list" command with two absolute arguments' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-list 1,3']) - self.assertListing(''' - 1 # Sample script for use by test_gdb.py - 2 - 3 def foo(a, b, c): -''', - bt) + self.assertListing(' 1 # Sample script for use by test_gdb.py\n' + ' 2 \n' + ' 3 def foo(a, b, c):\n', + bt) class StackNavigationTests(DebuggerTests): def test_pyup_command(self): 'Verify that the "py-up" command works' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-up']) self.assertMultilineMatches(bt, r'''^.* -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1L, b=2L, c=3L\) baz\(a, b, c\) $''') def test_down_at_bottom(self): 'Verify handling of "py-down" at the bottom of the stack' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-down']) self.assertEndsWith(bt, 'Unable to find a newer python frame\n') def test_up_at_top(self): 'Verify handling of "py-up" at the top of the stack' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-up'] * 4) self.assertEndsWith(bt, 'Unable to find an older python frame\n') def test_up_then_down(self): 'Verify "py-up" followed by "py-down"' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-up', 'py-down']) self.assertMultilineMatches(bt, - r'''^.* -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) + '''^.* +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1L, b=2L, c=3L\) baz\(a, b, c\) -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 10, in baz \(args=\(1, 2, 3\)\) - print\(42\) +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 10, in baz \(args=\(1L, 2L, 3L\)\) + id\(42\) $''') class PyBtTests(DebuggerTests): def test_basic_command(self): 'Verify that the "py-bt" command works' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-bt']) self.assertMultilineMatches(bt, - r'''^.* -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) + '''^.* +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1L, b=2L, c=3L\) baz\(a, b, c\) -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1L, b=2L, c=3L\) bar\(a, b, c\) -#[0-9]+ Frame 0x[0-9a-f]+, for file Lib/test/test_gdb_sample.py, line 12, in \(\) +#[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 12, in \(\) foo\(1, 2, 3\) ''') class PyPrintTests(DebuggerTests): def test_basic_command(self): 'Verify that the "py-print" command works' - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-print args']) self.assertMultilineMatches(bt, - r".*\nlocal 'args' = \(1, 2, 3\)\n.*") + r".*\nlocal 'args' = \(1L, 2L, 3L\)\n.*") def test_print_after_up(self): - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-up', 'py-print c', 'py-print b', 'py-print a']) self.assertMultilineMatches(bt, - r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*") + r".*\nlocal 'c' = 3L\nlocal 'b' = 2L\nlocal 'a' = 1L\n.*") def test_printing_global(self): - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-print __name__']) self.assertMultilineMatches(bt, - r".*\nglobal '__name__' = '__main__'\n.*") + r".*\nglobal '__name__' = u'__main__'\n.*") def test_printing_builtin(self): - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-print len']) self.assertMultilineMatches(bt, - r".*\nbuiltin 'len' = \n.*") + r".*\nbuiltin 'len' = \n.*") class PyLocalsTests(DebuggerTests): def test_basic_command(self): - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-locals']) self.assertMultilineMatches(bt, - r".*\nargs = \(1, 2, 3\)\n.*") + r".*\nargs = \(1L, 2L, 3L\)\n.*") def test_locals_after_up(self): - bt = self.get_stack_trace(script='Lib/test/test_gdb_sample.py', + bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-up', 'py-locals']) self.assertMultilineMatches(bt, - r".*\na = 1\nb = 2\nc = 3\n.*") + r".*\na = 1L\nb = 2L\nc = 3L\n.*") def test_main(): run_unittest(#PrettyPrintTests, Index: Lib/test/gdb_sample.py =================================================================== --- Lib/test/gdb_sample.py (revision 80008) +++ Lib/test/gdb_sample.py (working copy) @@ -7,6 +7,6 @@ baz(a, b, c) def baz(*args): - print(42) + id(42) foo(1, 2, 3)