diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 1a9975fb84d1e9..0131e4d0b0f72d 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -227,6 +227,15 @@ def get_stack_trace(self, source=None, script=None, " because the Program Counter is" " not present") + # bpo-40019: Skip the test if gdb failed to read debug information + # because the Python binary is optimized. + for pattern in ( + '(frame information optimized out)', + 'Unable to read information on python frame', + ): + if pattern in out: + raise unittest.SkipTest(f"{pattern!r} found in gdb output") + return out def get_gdb_repr(self, source, diff --git a/Misc/NEWS.d/next/Tests/2020-03-20-00-30-36.bpo-40019.zOqHpQ.rst b/Misc/NEWS.d/next/Tests/2020-03-20-00-30-36.bpo-40019.zOqHpQ.rst new file mode 100644 index 00000000000000..a9d0b3970ae537 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2020-03-20-00-30-36.bpo-40019.zOqHpQ.rst @@ -0,0 +1,2 @@ +test_gdb now skips tests if it detects that gdb failed to read debug +information because the Python binary is optimized. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index feec789e6ade93..86ace3796218f8 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -99,6 +99,8 @@ def _sizeof_void_p(): ENCODING = locale.getpreferredencoding() +FRAME_INFO_OPTIMIZED_OUT = '(frame information optimized out)' +UNABLE_READ_INFO_PYTHON_FRAME = 'Unable to read information on python frame' EVALFRAME = '_PyEval_EvalFrameDefault' class NullPyObjectPtr(RuntimeError): @@ -918,7 +920,7 @@ def get_var_by_name(self, name): def filename(self): '''Get the path of the current Python source file, as a string''' if self.is_optimized_out(): - return '(frame information optimized out)' + return FRAME_INFO_OPTIMIZED_OUT return self.co_filename.proxyval(set()) def current_line_num(self): @@ -949,7 +951,7 @@ def current_line(self): '''Get the text of the current source line as a string, with a trailing newline character''' if self.is_optimized_out(): - return '(frame information optimized out)' + return FRAME_INFO_OPTIMIZED_OUT lineno = self.current_line_num() if lineno is None: @@ -970,7 +972,7 @@ def current_line(self): def write_repr(self, out, visited): if self.is_optimized_out(): - out.write('(frame information optimized out)') + out.write(FRAME_INFO_OPTIMIZED_OUT) return lineno = self.current_line_num() lineno = str(lineno) if lineno is not None else "?" @@ -993,7 +995,7 @@ def write_repr(self, out, visited): def print_traceback(self): if self.is_optimized_out(): - sys.stdout.write(' (frame information optimized out)\n') + sys.stdout.write(' %s\n' % FRAME_INFO_OPTIMIZED_OUT) return visited = set() lineno = self.current_line_num() @@ -1744,7 +1746,7 @@ def invoke(self, args, from_tty): pyop = frame.get_pyop() if not pyop or pyop.is_optimized_out(): - print('Unable to read information on python frame') + print(UNABLE_READ_INFO_PYTHON_FRAME) return filename = pyop.filename() @@ -1904,7 +1906,7 @@ def invoke(self, args, from_tty): pyop_frame = frame.get_pyop() if not pyop_frame: - print('Unable to read information on python frame') + print(UNABLE_READ_INFO_PYTHON_FRAME) return pyop_var, scope = pyop_frame.get_var_by_name(name) @@ -1938,7 +1940,7 @@ def invoke(self, args, from_tty): pyop_frame = frame.get_pyop() if not pyop_frame: - print('Unable to read information on python frame') + print(UNABLE_READ_INFO_PYTHON_FRAME) return for pyop_name, pyop_value in pyop_frame.iter_locals():