17db96d56Sopenharmony_ci# Verify that gdb can pretty-print the various PyObject* types 27db96d56Sopenharmony_ci# 37db96d56Sopenharmony_ci# The code for testing gdb was adapted from similar work in Unladen Swallow's 47db96d56Sopenharmony_ci# Lib/test/test_jit_gdb.py 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ciimport os 77db96d56Sopenharmony_ciimport platform 87db96d56Sopenharmony_ciimport re 97db96d56Sopenharmony_ciimport subprocess 107db96d56Sopenharmony_ciimport sys 117db96d56Sopenharmony_ciimport sysconfig 127db96d56Sopenharmony_ciimport textwrap 137db96d56Sopenharmony_ciimport unittest 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_cifrom test import support 167db96d56Sopenharmony_cifrom test.support import findfile, python_is_optimized 177db96d56Sopenharmony_ci 187db96d56Sopenharmony_cidef get_gdb_version(): 197db96d56Sopenharmony_ci try: 207db96d56Sopenharmony_ci cmd = ["gdb", "-nx", "--version"] 217db96d56Sopenharmony_ci proc = subprocess.Popen(cmd, 227db96d56Sopenharmony_ci stdout=subprocess.PIPE, 237db96d56Sopenharmony_ci stderr=subprocess.PIPE, 247db96d56Sopenharmony_ci universal_newlines=True) 257db96d56Sopenharmony_ci with proc: 267db96d56Sopenharmony_ci version, stderr = proc.communicate() 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ci if proc.returncode: 297db96d56Sopenharmony_ci raise Exception(f"Command {' '.join(cmd)!r} failed " 307db96d56Sopenharmony_ci f"with exit code {proc.returncode}: " 317db96d56Sopenharmony_ci f"stdout={version!r} stderr={stderr!r}") 327db96d56Sopenharmony_ci except OSError: 337db96d56Sopenharmony_ci # This is what "no gdb" looks like. There may, however, be other 347db96d56Sopenharmony_ci # errors that manifest this way too. 357db96d56Sopenharmony_ci raise unittest.SkipTest("Couldn't find gdb on the path") 367db96d56Sopenharmony_ci 377db96d56Sopenharmony_ci # Regex to parse: 387db96d56Sopenharmony_ci # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 397db96d56Sopenharmony_ci # 'GNU gdb (GDB) Fedora 7.9.1-17.fc22\n' -> 7.9 407db96d56Sopenharmony_ci # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1 417db96d56Sopenharmony_ci # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5 427db96d56Sopenharmony_ci # 'HP gdb 6.7 for HP Itanium (32 or 64 bit) and target HP-UX 11iv2 and 11iv3.\n' -> 6.7 437db96d56Sopenharmony_ci match = re.search(r"^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)", version) 447db96d56Sopenharmony_ci if match is None: 457db96d56Sopenharmony_ci raise Exception("unable to parse GDB version: %r" % version) 467db96d56Sopenharmony_ci return (version, int(match.group(1)), int(match.group(2))) 477db96d56Sopenharmony_ci 487db96d56Sopenharmony_cigdb_version, gdb_major_version, gdb_minor_version = get_gdb_version() 497db96d56Sopenharmony_ciif gdb_major_version < 7: 507db96d56Sopenharmony_ci raise unittest.SkipTest("gdb versions before 7.0 didn't support python " 517db96d56Sopenharmony_ci "embedding. Saw %s.%s:\n%s" 527db96d56Sopenharmony_ci % (gdb_major_version, gdb_minor_version, 537db96d56Sopenharmony_ci gdb_version)) 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ciif not sysconfig.is_python_build(): 567db96d56Sopenharmony_ci raise unittest.SkipTest("test_gdb only works on source builds at the moment.") 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ciif 'Clang' in platform.python_compiler() and sys.platform == 'darwin': 597db96d56Sopenharmony_ci raise unittest.SkipTest("test_gdb doesn't work correctly when python is" 607db96d56Sopenharmony_ci " built with LLVM clang") 617db96d56Sopenharmony_ci 627db96d56Sopenharmony_ciif ((sysconfig.get_config_var('PGO_PROF_USE_FLAG') or 'xxx') in 637db96d56Sopenharmony_ci (sysconfig.get_config_var('PY_CORE_CFLAGS') or '')): 647db96d56Sopenharmony_ci raise unittest.SkipTest("test_gdb is not reliable on PGO builds") 657db96d56Sopenharmony_ci 667db96d56Sopenharmony_ci# Location of custom hooks file in a repository checkout. 677db96d56Sopenharmony_cicheckout_hook_path = os.path.join(os.path.dirname(sys.executable), 687db96d56Sopenharmony_ci 'python-gdb.py') 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ciPYTHONHASHSEED = '123' 717db96d56Sopenharmony_ci 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_cidef cet_protection(): 747db96d56Sopenharmony_ci cflags = sysconfig.get_config_var('CFLAGS') 757db96d56Sopenharmony_ci if not cflags: 767db96d56Sopenharmony_ci return False 777db96d56Sopenharmony_ci flags = cflags.split() 787db96d56Sopenharmony_ci # True if "-mcet -fcf-protection" options are found, but false 797db96d56Sopenharmony_ci # if "-fcf-protection=none" or "-fcf-protection=return" is found. 807db96d56Sopenharmony_ci return (('-mcet' in flags) 817db96d56Sopenharmony_ci and any((flag.startswith('-fcf-protection') 827db96d56Sopenharmony_ci and not flag.endswith(("=none", "=return"))) 837db96d56Sopenharmony_ci for flag in flags)) 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci# Control-flow enforcement technology 867db96d56Sopenharmony_ciCET_PROTECTION = cet_protection() 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_cidef run_gdb(*args, **env_vars): 907db96d56Sopenharmony_ci """Runs gdb in --batch mode with the additional arguments given by *args. 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci Returns its (stdout, stderr) decoded from utf-8 using the replace handler. 937db96d56Sopenharmony_ci """ 947db96d56Sopenharmony_ci if env_vars: 957db96d56Sopenharmony_ci env = os.environ.copy() 967db96d56Sopenharmony_ci env.update(env_vars) 977db96d56Sopenharmony_ci else: 987db96d56Sopenharmony_ci env = None 997db96d56Sopenharmony_ci # -nx: Do not execute commands from any .gdbinit initialization files 1007db96d56Sopenharmony_ci # (issue #22188) 1017db96d56Sopenharmony_ci base_cmd = ('gdb', '--batch', '-nx') 1027db96d56Sopenharmony_ci if (gdb_major_version, gdb_minor_version) >= (7, 4): 1037db96d56Sopenharmony_ci base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path) 1047db96d56Sopenharmony_ci proc = subprocess.Popen(base_cmd + args, 1057db96d56Sopenharmony_ci # Redirect stdin to prevent GDB from messing with 1067db96d56Sopenharmony_ci # the terminal settings 1077db96d56Sopenharmony_ci stdin=subprocess.PIPE, 1087db96d56Sopenharmony_ci stdout=subprocess.PIPE, 1097db96d56Sopenharmony_ci stderr=subprocess.PIPE, 1107db96d56Sopenharmony_ci env=env) 1117db96d56Sopenharmony_ci with proc: 1127db96d56Sopenharmony_ci out, err = proc.communicate() 1137db96d56Sopenharmony_ci return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci# Verify that "gdb" was built with the embedded python support enabled: 1167db96d56Sopenharmony_cigdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)") 1177db96d56Sopenharmony_ciif not gdbpy_version: 1187db96d56Sopenharmony_ci raise unittest.SkipTest("gdb not built with embedded python support") 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ciif "major=2" in gdbpy_version: 1217db96d56Sopenharmony_ci raise unittest.SkipTest("gdb built with Python 2") 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci# Verify that "gdb" can load our custom hooks, as OS security settings may 1247db96d56Sopenharmony_ci# disallow this without a customized .gdbinit. 1257db96d56Sopenharmony_ci_, gdbpy_errors = run_gdb('--args', sys.executable) 1267db96d56Sopenharmony_ciif "auto-loading has been declined" in gdbpy_errors: 1277db96d56Sopenharmony_ci msg = "gdb security settings prevent use of custom hooks: " 1287db96d56Sopenharmony_ci raise unittest.SkipTest(msg + gdbpy_errors.rstrip()) 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_cidef gdb_has_frame_select(): 1317db96d56Sopenharmony_ci # Does this build of gdb have gdb.Frame.select ? 1327db96d56Sopenharmony_ci stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))") 1337db96d56Sopenharmony_ci m = re.match(r'.*\[(.*)\].*', stdout) 1347db96d56Sopenharmony_ci if not m: 1357db96d56Sopenharmony_ci raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test") 1367db96d56Sopenharmony_ci gdb_frame_dir = m.group(1).split(', ') 1377db96d56Sopenharmony_ci return "'select'" in gdb_frame_dir 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ciHAS_PYUP_PYDOWN = gdb_has_frame_select() 1407db96d56Sopenharmony_ci 1417db96d56Sopenharmony_ciBREAKPOINT_FN='builtin_id' 1427db96d56Sopenharmony_ci 1437db96d56Sopenharmony_ci@unittest.skipIf(support.PGO, "not useful for PGO") 1447db96d56Sopenharmony_ciclass DebuggerTests(unittest.TestCase): 1457db96d56Sopenharmony_ci 1467db96d56Sopenharmony_ci """Test that the debugger can debug Python.""" 1477db96d56Sopenharmony_ci 1487db96d56Sopenharmony_ci def get_stack_trace(self, source=None, script=None, 1497db96d56Sopenharmony_ci breakpoint=BREAKPOINT_FN, 1507db96d56Sopenharmony_ci cmds_after_breakpoint=None, 1517db96d56Sopenharmony_ci import_site=False, 1527db96d56Sopenharmony_ci ignore_stderr=False): 1537db96d56Sopenharmony_ci ''' 1547db96d56Sopenharmony_ci Run 'python -c SOURCE' under gdb with a breakpoint. 1557db96d56Sopenharmony_ci 1567db96d56Sopenharmony_ci Support injecting commands after the breakpoint is reached 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci Returns the stdout from gdb 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci cmds_after_breakpoint: if provided, a list of strings: gdb commands 1617db96d56Sopenharmony_ci ''' 1627db96d56Sopenharmony_ci # We use "set breakpoint pending yes" to avoid blocking with a: 1637db96d56Sopenharmony_ci # Function "foo" not defined. 1647db96d56Sopenharmony_ci # Make breakpoint pending on future shared library load? (y or [n]) 1657db96d56Sopenharmony_ci # error, which typically happens python is dynamically linked (the 1667db96d56Sopenharmony_ci # breakpoints of interest are to be found in the shared library) 1677db96d56Sopenharmony_ci # When this happens, we still get: 1687db96d56Sopenharmony_ci # Function "textiowrapper_write" not defined. 1697db96d56Sopenharmony_ci # emitted to stderr each time, alas. 1707db96d56Sopenharmony_ci 1717db96d56Sopenharmony_ci # Initially I had "--eval-command=continue" here, but removed it to 1727db96d56Sopenharmony_ci # avoid repeated print breakpoints when traversing hierarchical data 1737db96d56Sopenharmony_ci # structures 1747db96d56Sopenharmony_ci 1757db96d56Sopenharmony_ci # Generate a list of commands in gdb's language: 1767db96d56Sopenharmony_ci commands = ['set breakpoint pending yes', 1777db96d56Sopenharmony_ci 'break %s' % breakpoint, 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_ci # The tests assume that the first frame of printed 1807db96d56Sopenharmony_ci # backtrace will not contain program counter, 1817db96d56Sopenharmony_ci # that is however not guaranteed by gdb 1827db96d56Sopenharmony_ci # therefore we need to use 'set print address off' to 1837db96d56Sopenharmony_ci # make sure the counter is not there. For example: 1847db96d56Sopenharmony_ci # #0 in PyObject_Print ... 1857db96d56Sopenharmony_ci # is assumed, but sometimes this can be e.g. 1867db96d56Sopenharmony_ci # #0 0x00003fffb7dd1798 in PyObject_Print ... 1877db96d56Sopenharmony_ci 'set print address off', 1887db96d56Sopenharmony_ci 1897db96d56Sopenharmony_ci 'run'] 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci # GDB as of 7.4 onwards can distinguish between the 1927db96d56Sopenharmony_ci # value of a variable at entry vs current value: 1937db96d56Sopenharmony_ci # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html 1947db96d56Sopenharmony_ci # which leads to the selftests failing with errors like this: 1957db96d56Sopenharmony_ci # AssertionError: 'v@entry=()' != '()' 1967db96d56Sopenharmony_ci # Disable this: 1977db96d56Sopenharmony_ci if (gdb_major_version, gdb_minor_version) >= (7, 4): 1987db96d56Sopenharmony_ci commands += ['set print entry-values no'] 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci if cmds_after_breakpoint: 2017db96d56Sopenharmony_ci if CET_PROTECTION: 2027db96d56Sopenharmony_ci # bpo-32962: When Python is compiled with -mcet 2037db96d56Sopenharmony_ci # -fcf-protection, function arguments are unusable before 2047db96d56Sopenharmony_ci # running the first instruction of the function entry point. 2057db96d56Sopenharmony_ci # The 'next' command makes the required first step. 2067db96d56Sopenharmony_ci commands += ['next'] 2077db96d56Sopenharmony_ci commands += cmds_after_breakpoint 2087db96d56Sopenharmony_ci else: 2097db96d56Sopenharmony_ci commands += ['backtrace'] 2107db96d56Sopenharmony_ci 2117db96d56Sopenharmony_ci # print commands 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ci # Use "commands" to generate the arguments with which to invoke "gdb": 2147db96d56Sopenharmony_ci args = ['--eval-command=%s' % cmd for cmd in commands] 2157db96d56Sopenharmony_ci args += ["--args", 2167db96d56Sopenharmony_ci sys.executable] 2177db96d56Sopenharmony_ci args.extend(subprocess._args_from_interpreter_flags()) 2187db96d56Sopenharmony_ci 2197db96d56Sopenharmony_ci if not import_site: 2207db96d56Sopenharmony_ci # -S suppresses the default 'import site' 2217db96d56Sopenharmony_ci args += ["-S"] 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci if source: 2247db96d56Sopenharmony_ci args += ["-c", source] 2257db96d56Sopenharmony_ci elif script: 2267db96d56Sopenharmony_ci args += [script] 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci # Use "args" to invoke gdb, capturing stdout, stderr: 2297db96d56Sopenharmony_ci out, err = run_gdb(*args, PYTHONHASHSEED=PYTHONHASHSEED) 2307db96d56Sopenharmony_ci 2317db96d56Sopenharmony_ci if not ignore_stderr: 2327db96d56Sopenharmony_ci for line in err.splitlines(): 2337db96d56Sopenharmony_ci print(line, file=sys.stderr) 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci # bpo-34007: Sometimes some versions of the shared libraries that 2367db96d56Sopenharmony_ci # are part of the traceback are compiled in optimised mode and the 2377db96d56Sopenharmony_ci # Program Counter (PC) is not present, not allowing gdb to walk the 2387db96d56Sopenharmony_ci # frames back. When this happens, the Python bindings of gdb raise 2397db96d56Sopenharmony_ci # an exception, making the test impossible to succeed. 2407db96d56Sopenharmony_ci if "PC not saved" in err: 2417db96d56Sopenharmony_ci raise unittest.SkipTest("gdb cannot walk the frame object" 2427db96d56Sopenharmony_ci " because the Program Counter is" 2437db96d56Sopenharmony_ci " not present") 2447db96d56Sopenharmony_ci 2457db96d56Sopenharmony_ci # bpo-40019: Skip the test if gdb failed to read debug information 2467db96d56Sopenharmony_ci # because the Python binary is optimized. 2477db96d56Sopenharmony_ci for pattern in ( 2487db96d56Sopenharmony_ci '(frame information optimized out)', 2497db96d56Sopenharmony_ci 'Unable to read information on python frame', 2507db96d56Sopenharmony_ci ): 2517db96d56Sopenharmony_ci if pattern in out: 2527db96d56Sopenharmony_ci raise unittest.SkipTest(f"{pattern!r} found in gdb output") 2537db96d56Sopenharmony_ci 2547db96d56Sopenharmony_ci return out 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci def get_gdb_repr(self, source, 2577db96d56Sopenharmony_ci cmds_after_breakpoint=None, 2587db96d56Sopenharmony_ci import_site=False): 2597db96d56Sopenharmony_ci # Given an input python source representation of data, 2607db96d56Sopenharmony_ci # run "python -c'id(DATA)'" under gdb with a breakpoint on 2617db96d56Sopenharmony_ci # builtin_id and scrape out gdb's representation of the "op" 2627db96d56Sopenharmony_ci # parameter, and verify that the gdb displays the same string 2637db96d56Sopenharmony_ci # 2647db96d56Sopenharmony_ci # Verify that the gdb displays the expected string 2657db96d56Sopenharmony_ci # 2667db96d56Sopenharmony_ci # For a nested structure, the first time we hit the breakpoint will 2677db96d56Sopenharmony_ci # give us the top-level structure 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_ci # NOTE: avoid decoding too much of the traceback as some 2707db96d56Sopenharmony_ci # undecodable characters may lurk there in optimized mode 2717db96d56Sopenharmony_ci # (issue #19743). 2727db96d56Sopenharmony_ci cmds_after_breakpoint = cmds_after_breakpoint or ["backtrace 1"] 2737db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(source, breakpoint=BREAKPOINT_FN, 2747db96d56Sopenharmony_ci cmds_after_breakpoint=cmds_after_breakpoint, 2757db96d56Sopenharmony_ci import_site=import_site) 2767db96d56Sopenharmony_ci # gdb can insert additional '\n' and space characters in various places 2777db96d56Sopenharmony_ci # in its output, depending on the width of the terminal it's connected 2787db96d56Sopenharmony_ci # to (using its "wrap_here" function) 2797db96d56Sopenharmony_ci m = re.search( 2807db96d56Sopenharmony_ci # Match '#0 builtin_id(self=..., v=...)' 2817db96d56Sopenharmony_ci r'#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)' 2827db96d56Sopenharmony_ci # Match ' at Python/bltinmodule.c'. 2837db96d56Sopenharmony_ci # bpo-38239: builtin_id() is defined in Python/bltinmodule.c, 2847db96d56Sopenharmony_ci # but accept any "Directory\file.c" to support Link Time 2857db96d56Sopenharmony_ci # Optimization (LTO). 2867db96d56Sopenharmony_ci r'\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.c', 2877db96d56Sopenharmony_ci gdb_output, re.DOTALL) 2887db96d56Sopenharmony_ci if not m: 2897db96d56Sopenharmony_ci self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output)) 2907db96d56Sopenharmony_ci return m.group(1), gdb_output 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci def assertEndsWith(self, actual, exp_end): 2937db96d56Sopenharmony_ci '''Ensure that the given "actual" string ends with "exp_end"''' 2947db96d56Sopenharmony_ci self.assertTrue(actual.endswith(exp_end), 2957db96d56Sopenharmony_ci msg='%r did not end with %r' % (actual, exp_end)) 2967db96d56Sopenharmony_ci 2977db96d56Sopenharmony_ci def assertMultilineMatches(self, actual, pattern): 2987db96d56Sopenharmony_ci m = re.match(pattern, actual, re.DOTALL) 2997db96d56Sopenharmony_ci if not m: 3007db96d56Sopenharmony_ci self.fail(msg='%r did not match %r' % (actual, pattern)) 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def get_sample_script(self): 3037db96d56Sopenharmony_ci return findfile('gdb_sample.py') 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_ciclass PrettyPrintTests(DebuggerTests): 3067db96d56Sopenharmony_ci def test_getting_backtrace(self): 3077db96d56Sopenharmony_ci gdb_output = self.get_stack_trace('id(42)') 3087db96d56Sopenharmony_ci self.assertTrue(BREAKPOINT_FN in gdb_output) 3097db96d56Sopenharmony_ci 3107db96d56Sopenharmony_ci def assertGdbRepr(self, val, exp_repr=None): 3117db96d56Sopenharmony_ci # Ensure that gdb's rendering of the value in a debugged process 3127db96d56Sopenharmony_ci # matches repr(value) in this process: 3137db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr('id(' + ascii(val) + ')') 3147db96d56Sopenharmony_ci if not exp_repr: 3157db96d56Sopenharmony_ci exp_repr = repr(val) 3167db96d56Sopenharmony_ci self.assertEqual(gdb_repr, exp_repr, 3177db96d56Sopenharmony_ci ('%r did not equal expected %r; full output was:\n%s' 3187db96d56Sopenharmony_ci % (gdb_repr, exp_repr, gdb_output))) 3197db96d56Sopenharmony_ci 3207db96d56Sopenharmony_ci def test_int(self): 3217db96d56Sopenharmony_ci 'Verify the pretty-printing of various int values' 3227db96d56Sopenharmony_ci self.assertGdbRepr(42) 3237db96d56Sopenharmony_ci self.assertGdbRepr(0) 3247db96d56Sopenharmony_ci self.assertGdbRepr(-7) 3257db96d56Sopenharmony_ci self.assertGdbRepr(1000000000000) 3267db96d56Sopenharmony_ci self.assertGdbRepr(-1000000000000000) 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci def test_singletons(self): 3297db96d56Sopenharmony_ci 'Verify the pretty-printing of True, False and None' 3307db96d56Sopenharmony_ci self.assertGdbRepr(True) 3317db96d56Sopenharmony_ci self.assertGdbRepr(False) 3327db96d56Sopenharmony_ci self.assertGdbRepr(None) 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci def test_dicts(self): 3357db96d56Sopenharmony_ci 'Verify the pretty-printing of dictionaries' 3367db96d56Sopenharmony_ci self.assertGdbRepr({}) 3377db96d56Sopenharmony_ci self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}") 3387db96d56Sopenharmony_ci # Python preserves insertion order since 3.6 3397db96d56Sopenharmony_ci self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'foo': 'bar', 'douglas': 42}") 3407db96d56Sopenharmony_ci 3417db96d56Sopenharmony_ci def test_lists(self): 3427db96d56Sopenharmony_ci 'Verify the pretty-printing of lists' 3437db96d56Sopenharmony_ci self.assertGdbRepr([]) 3447db96d56Sopenharmony_ci self.assertGdbRepr(list(range(5))) 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_ci def test_bytes(self): 3477db96d56Sopenharmony_ci 'Verify the pretty-printing of bytes' 3487db96d56Sopenharmony_ci self.assertGdbRepr(b'') 3497db96d56Sopenharmony_ci self.assertGdbRepr(b'And now for something hopefully the same') 3507db96d56Sopenharmony_ci self.assertGdbRepr(b'string with embedded NUL here \0 and then some more text') 3517db96d56Sopenharmony_ci self.assertGdbRepr(b'this is a tab:\t' 3527db96d56Sopenharmony_ci b' this is a slash-N:\n' 3537db96d56Sopenharmony_ci b' this is a slash-R:\r' 3547db96d56Sopenharmony_ci ) 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci self.assertGdbRepr(b'this is byte 255:\xff and byte 128:\x80') 3577db96d56Sopenharmony_ci 3587db96d56Sopenharmony_ci self.assertGdbRepr(bytes([b for b in range(255)])) 3597db96d56Sopenharmony_ci 3607db96d56Sopenharmony_ci def test_strings(self): 3617db96d56Sopenharmony_ci 'Verify the pretty-printing of unicode strings' 3627db96d56Sopenharmony_ci # We cannot simply call locale.getpreferredencoding() here, 3637db96d56Sopenharmony_ci # as GDB might have been linked against a different version 3647db96d56Sopenharmony_ci # of Python with a different encoding and coercion policy 3657db96d56Sopenharmony_ci # with respect to PEP 538 and PEP 540. 3667db96d56Sopenharmony_ci out, err = run_gdb( 3677db96d56Sopenharmony_ci '--eval-command', 3687db96d56Sopenharmony_ci 'python import locale; print(locale.getpreferredencoding())') 3697db96d56Sopenharmony_ci 3707db96d56Sopenharmony_ci encoding = out.rstrip() 3717db96d56Sopenharmony_ci if err or not encoding: 3727db96d56Sopenharmony_ci raise RuntimeError( 3737db96d56Sopenharmony_ci f'unable to determine the preferred encoding ' 3747db96d56Sopenharmony_ci f'of embedded Python in GDB: {err}') 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci def check_repr(text): 3777db96d56Sopenharmony_ci try: 3787db96d56Sopenharmony_ci text.encode(encoding) 3797db96d56Sopenharmony_ci except UnicodeEncodeError: 3807db96d56Sopenharmony_ci self.assertGdbRepr(text, ascii(text)) 3817db96d56Sopenharmony_ci else: 3827db96d56Sopenharmony_ci self.assertGdbRepr(text) 3837db96d56Sopenharmony_ci 3847db96d56Sopenharmony_ci self.assertGdbRepr('') 3857db96d56Sopenharmony_ci self.assertGdbRepr('And now for something hopefully the same') 3867db96d56Sopenharmony_ci self.assertGdbRepr('string with embedded NUL here \0 and then some more text') 3877db96d56Sopenharmony_ci 3887db96d56Sopenharmony_ci # Test printing a single character: 3897db96d56Sopenharmony_ci # U+2620 SKULL AND CROSSBONES 3907db96d56Sopenharmony_ci check_repr('\u2620') 3917db96d56Sopenharmony_ci 3927db96d56Sopenharmony_ci # Test printing a Japanese unicode string 3937db96d56Sopenharmony_ci # (I believe this reads "mojibake", using 3 characters from the CJK 3947db96d56Sopenharmony_ci # Unified Ideographs area, followed by U+3051 HIRAGANA LETTER KE) 3957db96d56Sopenharmony_ci check_repr('\u6587\u5b57\u5316\u3051') 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci # Test a character outside the BMP: 3987db96d56Sopenharmony_ci # U+1D121 MUSICAL SYMBOL C CLEF 3997db96d56Sopenharmony_ci # This is: 4007db96d56Sopenharmony_ci # UTF-8: 0xF0 0x9D 0x84 0xA1 4017db96d56Sopenharmony_ci # UTF-16: 0xD834 0xDD21 4027db96d56Sopenharmony_ci check_repr(chr(0x1D121)) 4037db96d56Sopenharmony_ci 4047db96d56Sopenharmony_ci def test_tuples(self): 4057db96d56Sopenharmony_ci 'Verify the pretty-printing of tuples' 4067db96d56Sopenharmony_ci self.assertGdbRepr(tuple(), '()') 4077db96d56Sopenharmony_ci self.assertGdbRepr((1,), '(1,)') 4087db96d56Sopenharmony_ci self.assertGdbRepr(('foo', 'bar', 'baz')) 4097db96d56Sopenharmony_ci 4107db96d56Sopenharmony_ci def test_sets(self): 4117db96d56Sopenharmony_ci 'Verify the pretty-printing of sets' 4127db96d56Sopenharmony_ci if (gdb_major_version, gdb_minor_version) < (7, 3): 4137db96d56Sopenharmony_ci self.skipTest("pretty-printing of sets needs gdb 7.3 or later") 4147db96d56Sopenharmony_ci self.assertGdbRepr(set(), "set()") 4157db96d56Sopenharmony_ci self.assertGdbRepr(set(['a']), "{'a'}") 4167db96d56Sopenharmony_ci # PYTHONHASHSEED is need to get the exact frozenset item order 4177db96d56Sopenharmony_ci if not sys.flags.ignore_environment: 4187db96d56Sopenharmony_ci self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}") 4197db96d56Sopenharmony_ci self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}") 4207db96d56Sopenharmony_ci 4217db96d56Sopenharmony_ci # Ensure that we handle sets containing the "dummy" key value, 4227db96d56Sopenharmony_ci # which happens on deletion: 4237db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b']) 4247db96d56Sopenharmony_cis.remove('a') 4257db96d56Sopenharmony_ciid(s)''') 4267db96d56Sopenharmony_ci self.assertEqual(gdb_repr, "{'b'}") 4277db96d56Sopenharmony_ci 4287db96d56Sopenharmony_ci def test_frozensets(self): 4297db96d56Sopenharmony_ci 'Verify the pretty-printing of frozensets' 4307db96d56Sopenharmony_ci if (gdb_major_version, gdb_minor_version) < (7, 3): 4317db96d56Sopenharmony_ci self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later") 4327db96d56Sopenharmony_ci self.assertGdbRepr(frozenset(), "frozenset()") 4337db96d56Sopenharmony_ci self.assertGdbRepr(frozenset(['a']), "frozenset({'a'})") 4347db96d56Sopenharmony_ci # PYTHONHASHSEED is need to get the exact frozenset item order 4357db96d56Sopenharmony_ci if not sys.flags.ignore_environment: 4367db96d56Sopenharmony_ci self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})") 4377db96d56Sopenharmony_ci self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})") 4387db96d56Sopenharmony_ci 4397db96d56Sopenharmony_ci def test_exceptions(self): 4407db96d56Sopenharmony_ci # Test a RuntimeError 4417db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr(''' 4427db96d56Sopenharmony_citry: 4437db96d56Sopenharmony_ci raise RuntimeError("I am an error") 4447db96d56Sopenharmony_ciexcept RuntimeError as e: 4457db96d56Sopenharmony_ci id(e) 4467db96d56Sopenharmony_ci''') 4477db96d56Sopenharmony_ci self.assertEqual(gdb_repr, 4487db96d56Sopenharmony_ci "RuntimeError('I am an error',)") 4497db96d56Sopenharmony_ci 4507db96d56Sopenharmony_ci 4517db96d56Sopenharmony_ci # Test division by zero: 4527db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr(''' 4537db96d56Sopenharmony_citry: 4547db96d56Sopenharmony_ci a = 1 / 0 4557db96d56Sopenharmony_ciexcept ZeroDivisionError as e: 4567db96d56Sopenharmony_ci id(e) 4577db96d56Sopenharmony_ci''') 4587db96d56Sopenharmony_ci self.assertEqual(gdb_repr, 4597db96d56Sopenharmony_ci "ZeroDivisionError('division by zero',)") 4607db96d56Sopenharmony_ci 4617db96d56Sopenharmony_ci def test_modern_class(self): 4627db96d56Sopenharmony_ci 'Verify the pretty-printing of new-style class instances' 4637db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr(''' 4647db96d56Sopenharmony_ciclass Foo: 4657db96d56Sopenharmony_ci pass 4667db96d56Sopenharmony_cifoo = Foo() 4677db96d56Sopenharmony_cifoo.an_int = 42 4687db96d56Sopenharmony_ciid(foo)''') 4697db96d56Sopenharmony_ci m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr) 4707db96d56Sopenharmony_ci self.assertTrue(m, 4717db96d56Sopenharmony_ci msg='Unexpected new-style class rendering %r' % gdb_repr) 4727db96d56Sopenharmony_ci 4737db96d56Sopenharmony_ci def test_subclassing_list(self): 4747db96d56Sopenharmony_ci 'Verify the pretty-printing of an instance of a list subclass' 4757db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr(''' 4767db96d56Sopenharmony_ciclass Foo(list): 4777db96d56Sopenharmony_ci pass 4787db96d56Sopenharmony_cifoo = Foo() 4797db96d56Sopenharmony_cifoo += [1, 2, 3] 4807db96d56Sopenharmony_cifoo.an_int = 42 4817db96d56Sopenharmony_ciid(foo)''') 4827db96d56Sopenharmony_ci m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr) 4837db96d56Sopenharmony_ci 4847db96d56Sopenharmony_ci self.assertTrue(m, 4857db96d56Sopenharmony_ci msg='Unexpected new-style class rendering %r' % gdb_repr) 4867db96d56Sopenharmony_ci 4877db96d56Sopenharmony_ci def test_subclassing_tuple(self): 4887db96d56Sopenharmony_ci 'Verify the pretty-printing of an instance of a tuple subclass' 4897db96d56Sopenharmony_ci # This should exercise the negative tp_dictoffset code in the 4907db96d56Sopenharmony_ci # new-style class support 4917db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr(''' 4927db96d56Sopenharmony_ciclass Foo(tuple): 4937db96d56Sopenharmony_ci pass 4947db96d56Sopenharmony_cifoo = Foo((1, 2, 3)) 4957db96d56Sopenharmony_cifoo.an_int = 42 4967db96d56Sopenharmony_ciid(foo)''') 4977db96d56Sopenharmony_ci m = re.match(r'<Foo\(an_int=42\) at remote 0x-?[0-9a-f]+>', gdb_repr) 4987db96d56Sopenharmony_ci 4997db96d56Sopenharmony_ci self.assertTrue(m, 5007db96d56Sopenharmony_ci msg='Unexpected new-style class rendering %r' % gdb_repr) 5017db96d56Sopenharmony_ci 5027db96d56Sopenharmony_ci def assertSane(self, source, corruption, exprepr=None): 5037db96d56Sopenharmony_ci '''Run Python under gdb, corrupting variables in the inferior process 5047db96d56Sopenharmony_ci immediately before taking a backtrace. 5057db96d56Sopenharmony_ci 5067db96d56Sopenharmony_ci Verify that the variable's representation is the expected failsafe 5077db96d56Sopenharmony_ci representation''' 5087db96d56Sopenharmony_ci if corruption: 5097db96d56Sopenharmony_ci cmds_after_breakpoint=[corruption, 'backtrace'] 5107db96d56Sopenharmony_ci else: 5117db96d56Sopenharmony_ci cmds_after_breakpoint=['backtrace'] 5127db96d56Sopenharmony_ci 5137db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 5147db96d56Sopenharmony_ci self.get_gdb_repr(source, 5157db96d56Sopenharmony_ci cmds_after_breakpoint=cmds_after_breakpoint) 5167db96d56Sopenharmony_ci if exprepr: 5177db96d56Sopenharmony_ci if gdb_repr == exprepr: 5187db96d56Sopenharmony_ci # gdb managed to print the value in spite of the corruption; 5197db96d56Sopenharmony_ci # this is good (see http://bugs.python.org/issue8330) 5207db96d56Sopenharmony_ci return 5217db96d56Sopenharmony_ci 5227db96d56Sopenharmony_ci # Match anything for the type name; 0xDEADBEEF could point to 5237db96d56Sopenharmony_ci # something arbitrary (see http://bugs.python.org/issue8330) 5247db96d56Sopenharmony_ci pattern = '<.* at remote 0x-?[0-9a-f]+>' 5257db96d56Sopenharmony_ci 5267db96d56Sopenharmony_ci m = re.match(pattern, gdb_repr) 5277db96d56Sopenharmony_ci if not m: 5287db96d56Sopenharmony_ci self.fail('Unexpected gdb representation: %r\n%s' % \ 5297db96d56Sopenharmony_ci (gdb_repr, gdb_output)) 5307db96d56Sopenharmony_ci 5317db96d56Sopenharmony_ci def test_NULL_ptr(self): 5327db96d56Sopenharmony_ci 'Ensure that a NULL PyObject* is handled gracefully' 5337db96d56Sopenharmony_ci gdb_repr, gdb_output = ( 5347db96d56Sopenharmony_ci self.get_gdb_repr('id(42)', 5357db96d56Sopenharmony_ci cmds_after_breakpoint=['set variable v=0', 5367db96d56Sopenharmony_ci 'backtrace']) 5377db96d56Sopenharmony_ci ) 5387db96d56Sopenharmony_ci 5397db96d56Sopenharmony_ci self.assertEqual(gdb_repr, '0x0') 5407db96d56Sopenharmony_ci 5417db96d56Sopenharmony_ci def test_NULL_ob_type(self): 5427db96d56Sopenharmony_ci 'Ensure that a PyObject* with NULL ob_type is handled gracefully' 5437db96d56Sopenharmony_ci self.assertSane('id(42)', 5447db96d56Sopenharmony_ci 'set v->ob_type=0') 5457db96d56Sopenharmony_ci 5467db96d56Sopenharmony_ci def test_corrupt_ob_type(self): 5477db96d56Sopenharmony_ci 'Ensure that a PyObject* with a corrupt ob_type is handled gracefully' 5487db96d56Sopenharmony_ci self.assertSane('id(42)', 5497db96d56Sopenharmony_ci 'set v->ob_type=0xDEADBEEF', 5507db96d56Sopenharmony_ci exprepr='42') 5517db96d56Sopenharmony_ci 5527db96d56Sopenharmony_ci def test_corrupt_tp_flags(self): 5537db96d56Sopenharmony_ci 'Ensure that a PyObject* with a type with corrupt tp_flags is handled' 5547db96d56Sopenharmony_ci self.assertSane('id(42)', 5557db96d56Sopenharmony_ci 'set v->ob_type->tp_flags=0x0', 5567db96d56Sopenharmony_ci exprepr='42') 5577db96d56Sopenharmony_ci 5587db96d56Sopenharmony_ci def test_corrupt_tp_name(self): 5597db96d56Sopenharmony_ci 'Ensure that a PyObject* with a type with corrupt tp_name is handled' 5607db96d56Sopenharmony_ci self.assertSane('id(42)', 5617db96d56Sopenharmony_ci 'set v->ob_type->tp_name=0xDEADBEEF', 5627db96d56Sopenharmony_ci exprepr='42') 5637db96d56Sopenharmony_ci 5647db96d56Sopenharmony_ci def test_builtins_help(self): 5657db96d56Sopenharmony_ci 'Ensure that the new-style class _Helper in site.py can be handled' 5667db96d56Sopenharmony_ci 5677db96d56Sopenharmony_ci if sys.flags.no_site: 5687db96d56Sopenharmony_ci self.skipTest("need site module, but -S option was used") 5697db96d56Sopenharmony_ci 5707db96d56Sopenharmony_ci # (this was the issue causing tracebacks in 5717db96d56Sopenharmony_ci # http://bugs.python.org/issue8032#msg100537 ) 5727db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True) 5737db96d56Sopenharmony_ci 5747db96d56Sopenharmony_ci m = re.match(r'<_Helper\(\) at remote 0x-?[0-9a-f]+>', gdb_repr) 5757db96d56Sopenharmony_ci self.assertTrue(m, 5767db96d56Sopenharmony_ci msg='Unexpected rendering %r' % gdb_repr) 5777db96d56Sopenharmony_ci 5787db96d56Sopenharmony_ci def test_selfreferential_list(self): 5797db96d56Sopenharmony_ci '''Ensure that a reference loop involving a list doesn't lead proxyval 5807db96d56Sopenharmony_ci into an infinite loop:''' 5817db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 5827db96d56Sopenharmony_ci self.get_gdb_repr("a = [3, 4, 5] ; a.append(a) ; id(a)") 5837db96d56Sopenharmony_ci self.assertEqual(gdb_repr, '[3, 4, 5, [...]]') 5847db96d56Sopenharmony_ci 5857db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 5867db96d56Sopenharmony_ci self.get_gdb_repr("a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)") 5877db96d56Sopenharmony_ci self.assertEqual(gdb_repr, '[3, 4, 5, [[...]]]') 5887db96d56Sopenharmony_ci 5897db96d56Sopenharmony_ci def test_selfreferential_dict(self): 5907db96d56Sopenharmony_ci '''Ensure that a reference loop involving a dict doesn't lead proxyval 5917db96d56Sopenharmony_ci into an infinite loop:''' 5927db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 5937db96d56Sopenharmony_ci self.get_gdb_repr("a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)") 5947db96d56Sopenharmony_ci 5957db96d56Sopenharmony_ci self.assertEqual(gdb_repr, "{'foo': {'bar': {...}}}") 5967db96d56Sopenharmony_ci 5977db96d56Sopenharmony_ci def test_selfreferential_old_style_instance(self): 5987db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 5997db96d56Sopenharmony_ci self.get_gdb_repr(''' 6007db96d56Sopenharmony_ciclass Foo: 6017db96d56Sopenharmony_ci pass 6027db96d56Sopenharmony_cifoo = Foo() 6037db96d56Sopenharmony_cifoo.an_attr = foo 6047db96d56Sopenharmony_ciid(foo)''') 6057db96d56Sopenharmony_ci self.assertTrue(re.match(r'<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>', 6067db96d56Sopenharmony_ci gdb_repr), 6077db96d56Sopenharmony_ci 'Unexpected gdb representation: %r\n%s' % \ 6087db96d56Sopenharmony_ci (gdb_repr, gdb_output)) 6097db96d56Sopenharmony_ci 6107db96d56Sopenharmony_ci def test_selfreferential_new_style_instance(self): 6117db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 6127db96d56Sopenharmony_ci self.get_gdb_repr(''' 6137db96d56Sopenharmony_ciclass Foo(object): 6147db96d56Sopenharmony_ci pass 6157db96d56Sopenharmony_cifoo = Foo() 6167db96d56Sopenharmony_cifoo.an_attr = foo 6177db96d56Sopenharmony_ciid(foo)''') 6187db96d56Sopenharmony_ci self.assertTrue(re.match(r'<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>', 6197db96d56Sopenharmony_ci gdb_repr), 6207db96d56Sopenharmony_ci 'Unexpected gdb representation: %r\n%s' % \ 6217db96d56Sopenharmony_ci (gdb_repr, gdb_output)) 6227db96d56Sopenharmony_ci 6237db96d56Sopenharmony_ci gdb_repr, gdb_output = \ 6247db96d56Sopenharmony_ci self.get_gdb_repr(''' 6257db96d56Sopenharmony_ciclass Foo(object): 6267db96d56Sopenharmony_ci pass 6277db96d56Sopenharmony_cia = Foo() 6287db96d56Sopenharmony_cib = Foo() 6297db96d56Sopenharmony_cia.an_attr = b 6307db96d56Sopenharmony_cib.an_attr = a 6317db96d56Sopenharmony_ciid(a)''') 6327db96d56Sopenharmony_ci self.assertTrue(re.match(r'<Foo\(an_attr=<Foo\(an_attr=<\.\.\.>\) at remote 0x-?[0-9a-f]+>\) at remote 0x-?[0-9a-f]+>', 6337db96d56Sopenharmony_ci gdb_repr), 6347db96d56Sopenharmony_ci 'Unexpected gdb representation: %r\n%s' % \ 6357db96d56Sopenharmony_ci (gdb_repr, gdb_output)) 6367db96d56Sopenharmony_ci 6377db96d56Sopenharmony_ci def test_truncation(self): 6387db96d56Sopenharmony_ci 'Verify that very long output is truncated' 6397db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr('id(list(range(1000)))') 6407db96d56Sopenharmony_ci self.assertEqual(gdb_repr, 6417db96d56Sopenharmony_ci "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " 6427db96d56Sopenharmony_ci "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, " 6437db96d56Sopenharmony_ci "27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, " 6447db96d56Sopenharmony_ci "40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, " 6457db96d56Sopenharmony_ci "53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, " 6467db96d56Sopenharmony_ci "66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, " 6477db96d56Sopenharmony_ci "79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, " 6487db96d56Sopenharmony_ci "92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, " 6497db96d56Sopenharmony_ci "104, 105, 106, 107, 108, 109, 110, 111, 112, 113, " 6507db96d56Sopenharmony_ci "114, 115, 116, 117, 118, 119, 120, 121, 122, 123, " 6517db96d56Sopenharmony_ci "124, 125, 126, 127, 128, 129, 130, 131, 132, 133, " 6527db96d56Sopenharmony_ci "134, 135, 136, 137, 138, 139, 140, 141, 142, 143, " 6537db96d56Sopenharmony_ci "144, 145, 146, 147, 148, 149, 150, 151, 152, 153, " 6547db96d56Sopenharmony_ci "154, 155, 156, 157, 158, 159, 160, 161, 162, 163, " 6557db96d56Sopenharmony_ci "164, 165, 166, 167, 168, 169, 170, 171, 172, 173, " 6567db96d56Sopenharmony_ci "174, 175, 176, 177, 178, 179, 180, 181, 182, 183, " 6577db96d56Sopenharmony_ci "184, 185, 186, 187, 188, 189, 190, 191, 192, 193, " 6587db96d56Sopenharmony_ci "194, 195, 196, 197, 198, 199, 200, 201, 202, 203, " 6597db96d56Sopenharmony_ci "204, 205, 206, 207, 208, 209, 210, 211, 212, 213, " 6607db96d56Sopenharmony_ci "214, 215, 216, 217, 218, 219, 220, 221, 222, 223, " 6617db96d56Sopenharmony_ci "224, 225, 226...(truncated)") 6627db96d56Sopenharmony_ci self.assertEqual(len(gdb_repr), 6637db96d56Sopenharmony_ci 1024 + len('...(truncated)')) 6647db96d56Sopenharmony_ci 6657db96d56Sopenharmony_ci def test_builtin_method(self): 6667db96d56Sopenharmony_ci gdb_repr, gdb_output = self.get_gdb_repr('import sys; id(sys.stdout.readlines)') 6677db96d56Sopenharmony_ci self.assertTrue(re.match(r'<built-in method readlines of _io.TextIOWrapper object at remote 0x-?[0-9a-f]+>', 6687db96d56Sopenharmony_ci gdb_repr), 6697db96d56Sopenharmony_ci 'Unexpected gdb representation: %r\n%s' % \ 6707db96d56Sopenharmony_ci (gdb_repr, gdb_output)) 6717db96d56Sopenharmony_ci 6727db96d56Sopenharmony_ci def test_frames(self): 6737db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(''' 6747db96d56Sopenharmony_ciimport sys 6757db96d56Sopenharmony_cidef foo(a, b, c): 6767db96d56Sopenharmony_ci return sys._getframe(0) 6777db96d56Sopenharmony_ci 6787db96d56Sopenharmony_cif = foo(3, 4, 5) 6797db96d56Sopenharmony_ciid(f)''', 6807db96d56Sopenharmony_ci breakpoint='builtin_id', 6817db96d56Sopenharmony_ci cmds_after_breakpoint=['print (PyFrameObject*)v'] 6827db96d56Sopenharmony_ci ) 6837db96d56Sopenharmony_ci self.assertTrue(re.match(r'.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file <string>, line 4, in foo \(a=3.*', 6847db96d56Sopenharmony_ci gdb_output, 6857db96d56Sopenharmony_ci re.DOTALL), 6867db96d56Sopenharmony_ci 'Unexpected gdb representation: %r\n%s' % (gdb_output, gdb_output)) 6877db96d56Sopenharmony_ci 6887db96d56Sopenharmony_ci@unittest.skipIf(python_is_optimized(), 6897db96d56Sopenharmony_ci "Python was compiled with optimizations") 6907db96d56Sopenharmony_ciclass PyListTests(DebuggerTests): 6917db96d56Sopenharmony_ci def assertListing(self, expected, actual): 6927db96d56Sopenharmony_ci self.assertEndsWith(actual, expected) 6937db96d56Sopenharmony_ci 6947db96d56Sopenharmony_ci def test_basic_command(self): 6957db96d56Sopenharmony_ci 'Verify that the "py-list" command works' 6967db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 6977db96d56Sopenharmony_ci cmds_after_breakpoint=['py-list']) 6987db96d56Sopenharmony_ci 6997db96d56Sopenharmony_ci self.assertListing(' 5 \n' 7007db96d56Sopenharmony_ci ' 6 def bar(a, b, c):\n' 7017db96d56Sopenharmony_ci ' 7 baz(a, b, c)\n' 7027db96d56Sopenharmony_ci ' 8 \n' 7037db96d56Sopenharmony_ci ' 9 def baz(*args):\n' 7047db96d56Sopenharmony_ci ' >10 id(42)\n' 7057db96d56Sopenharmony_ci ' 11 \n' 7067db96d56Sopenharmony_ci ' 12 foo(1, 2, 3)\n', 7077db96d56Sopenharmony_ci bt) 7087db96d56Sopenharmony_ci 7097db96d56Sopenharmony_ci def test_one_abs_arg(self): 7107db96d56Sopenharmony_ci 'Verify the "py-list" command with one absolute argument' 7117db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 7127db96d56Sopenharmony_ci cmds_after_breakpoint=['py-list 9']) 7137db96d56Sopenharmony_ci 7147db96d56Sopenharmony_ci self.assertListing(' 9 def baz(*args):\n' 7157db96d56Sopenharmony_ci ' >10 id(42)\n' 7167db96d56Sopenharmony_ci ' 11 \n' 7177db96d56Sopenharmony_ci ' 12 foo(1, 2, 3)\n', 7187db96d56Sopenharmony_ci bt) 7197db96d56Sopenharmony_ci 7207db96d56Sopenharmony_ci def test_two_abs_args(self): 7217db96d56Sopenharmony_ci 'Verify the "py-list" command with two absolute arguments' 7227db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 7237db96d56Sopenharmony_ci cmds_after_breakpoint=['py-list 1,3']) 7247db96d56Sopenharmony_ci 7257db96d56Sopenharmony_ci self.assertListing(' 1 # Sample script for use by test_gdb.py\n' 7267db96d56Sopenharmony_ci ' 2 \n' 7277db96d56Sopenharmony_ci ' 3 def foo(a, b, c):\n', 7287db96d56Sopenharmony_ci bt) 7297db96d56Sopenharmony_ci 7307db96d56Sopenharmony_ciSAMPLE_WITH_C_CALL = """ 7317db96d56Sopenharmony_ci 7327db96d56Sopenharmony_cifrom _testcapi import pyobject_fastcall 7337db96d56Sopenharmony_ci 7347db96d56Sopenharmony_cidef foo(a, b, c): 7357db96d56Sopenharmony_ci bar(a, b, c) 7367db96d56Sopenharmony_ci 7377db96d56Sopenharmony_cidef bar(a, b, c): 7387db96d56Sopenharmony_ci pyobject_fastcall(baz, (a, b, c)) 7397db96d56Sopenharmony_ci 7407db96d56Sopenharmony_cidef baz(*args): 7417db96d56Sopenharmony_ci id(42) 7427db96d56Sopenharmony_ci 7437db96d56Sopenharmony_cifoo(1, 2, 3) 7447db96d56Sopenharmony_ci 7457db96d56Sopenharmony_ci""" 7467db96d56Sopenharmony_ci 7477db96d56Sopenharmony_ci 7487db96d56Sopenharmony_ciclass StackNavigationTests(DebuggerTests): 7497db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 7507db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 7517db96d56Sopenharmony_ci "Python was compiled with optimizations") 7527db96d56Sopenharmony_ci def test_pyup_command(self): 7537db96d56Sopenharmony_ci 'Verify that the "py-up" command works' 7547db96d56Sopenharmony_ci bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, 7557db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-up']) 7567db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 7577db96d56Sopenharmony_ci r'''^.* 7587db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) 7597db96d56Sopenharmony_ci#[0-9]+ <built-in method pyobject_fastcall of module object at remote 0x[0-9a-f]+> 7607db96d56Sopenharmony_ci$''') 7617db96d56Sopenharmony_ci 7627db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 7637db96d56Sopenharmony_ci def test_down_at_bottom(self): 7647db96d56Sopenharmony_ci 'Verify handling of "py-down" at the bottom of the stack' 7657db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 7667db96d56Sopenharmony_ci cmds_after_breakpoint=['py-down']) 7677db96d56Sopenharmony_ci self.assertEndsWith(bt, 7687db96d56Sopenharmony_ci 'Unable to find a newer python frame\n') 7697db96d56Sopenharmony_ci 7707db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 7717db96d56Sopenharmony_ci def test_up_at_top(self): 7727db96d56Sopenharmony_ci 'Verify handling of "py-up" at the top of the stack' 7737db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 7747db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up'] * 5) 7757db96d56Sopenharmony_ci self.assertEndsWith(bt, 7767db96d56Sopenharmony_ci 'Unable to find an older python frame\n') 7777db96d56Sopenharmony_ci 7787db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 7797db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 7807db96d56Sopenharmony_ci "Python was compiled with optimizations") 7817db96d56Sopenharmony_ci def test_up_then_down(self): 7827db96d56Sopenharmony_ci 'Verify "py-up" followed by "py-down"' 7837db96d56Sopenharmony_ci bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, 7847db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-up', 'py-down']) 7857db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 7867db96d56Sopenharmony_ci r'''^.* 7877db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) 7887db96d56Sopenharmony_ci#[0-9]+ <built-in method pyobject_fastcall of module object at remote 0x[0-9a-f]+> 7897db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) 7907db96d56Sopenharmony_ci$''') 7917db96d56Sopenharmony_ci 7927db96d56Sopenharmony_ciclass PyBtTests(DebuggerTests): 7937db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 7947db96d56Sopenharmony_ci "Python was compiled with optimizations") 7957db96d56Sopenharmony_ci def test_bt(self): 7967db96d56Sopenharmony_ci 'Verify that the "py-bt" command works' 7977db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 7987db96d56Sopenharmony_ci cmds_after_breakpoint=['py-bt']) 7997db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 8007db96d56Sopenharmony_ci r'''^.* 8017db96d56Sopenharmony_ciTraceback \(most recent call first\): 8027db96d56Sopenharmony_ci <built-in method id of module object .*> 8037db96d56Sopenharmony_ci File ".*gdb_sample.py", line 10, in baz 8047db96d56Sopenharmony_ci id\(42\) 8057db96d56Sopenharmony_ci File ".*gdb_sample.py", line 7, in bar 8067db96d56Sopenharmony_ci baz\(a, b, c\) 8077db96d56Sopenharmony_ci File ".*gdb_sample.py", line 4, in foo 8087db96d56Sopenharmony_ci bar\(a=a, b=b, c=c\) 8097db96d56Sopenharmony_ci File ".*gdb_sample.py", line 12, in <module> 8107db96d56Sopenharmony_ci foo\(1, 2, 3\) 8117db96d56Sopenharmony_ci''') 8127db96d56Sopenharmony_ci 8137db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 8147db96d56Sopenharmony_ci "Python was compiled with optimizations") 8157db96d56Sopenharmony_ci def test_bt_full(self): 8167db96d56Sopenharmony_ci 'Verify that the "py-bt-full" command works' 8177db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 8187db96d56Sopenharmony_ci cmds_after_breakpoint=['py-bt-full']) 8197db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 8207db96d56Sopenharmony_ci r'''^.* 8217db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) 8227db96d56Sopenharmony_ci baz\(a, b, c\) 8237db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) 8247db96d56Sopenharmony_ci bar\(a=a, b=b, c=c\) 8257db96d56Sopenharmony_ci#[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in <module> \(\) 8267db96d56Sopenharmony_ci foo\(1, 2, 3\) 8277db96d56Sopenharmony_ci''') 8287db96d56Sopenharmony_ci 8297db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 8307db96d56Sopenharmony_ci "Python was compiled with optimizations") 8317db96d56Sopenharmony_ci def test_threads(self): 8327db96d56Sopenharmony_ci 'Verify that "py-bt" indicates threads that are waiting for the GIL' 8337db96d56Sopenharmony_ci cmd = ''' 8347db96d56Sopenharmony_cifrom threading import Thread 8357db96d56Sopenharmony_ci 8367db96d56Sopenharmony_ciclass TestThread(Thread): 8377db96d56Sopenharmony_ci # These threads would run forever, but we'll interrupt things with the 8387db96d56Sopenharmony_ci # debugger 8397db96d56Sopenharmony_ci def run(self): 8407db96d56Sopenharmony_ci i = 0 8417db96d56Sopenharmony_ci while 1: 8427db96d56Sopenharmony_ci i += 1 8437db96d56Sopenharmony_ci 8447db96d56Sopenharmony_cit = {} 8457db96d56Sopenharmony_cifor i in range(4): 8467db96d56Sopenharmony_ci t[i] = TestThread() 8477db96d56Sopenharmony_ci t[i].start() 8487db96d56Sopenharmony_ci 8497db96d56Sopenharmony_ci# Trigger a breakpoint on the main thread 8507db96d56Sopenharmony_ciid(42) 8517db96d56Sopenharmony_ci 8527db96d56Sopenharmony_ci''' 8537db96d56Sopenharmony_ci # Verify with "py-bt": 8547db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(cmd, 8557db96d56Sopenharmony_ci cmds_after_breakpoint=['thread apply all py-bt']) 8567db96d56Sopenharmony_ci self.assertIn('Waiting for the GIL', gdb_output) 8577db96d56Sopenharmony_ci 8587db96d56Sopenharmony_ci # Verify with "py-bt-full": 8597db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(cmd, 8607db96d56Sopenharmony_ci cmds_after_breakpoint=['thread apply all py-bt-full']) 8617db96d56Sopenharmony_ci self.assertIn('Waiting for the GIL', gdb_output) 8627db96d56Sopenharmony_ci 8637db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 8647db96d56Sopenharmony_ci "Python was compiled with optimizations") 8657db96d56Sopenharmony_ci # Some older versions of gdb will fail with 8667db96d56Sopenharmony_ci # "Cannot find new threads: generic error" 8677db96d56Sopenharmony_ci # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround 8687db96d56Sopenharmony_ci def test_gc(self): 8697db96d56Sopenharmony_ci 'Verify that "py-bt" indicates if a thread is garbage-collecting' 8707db96d56Sopenharmony_ci cmd = ('from gc import collect\n' 8717db96d56Sopenharmony_ci 'id(42)\n' 8727db96d56Sopenharmony_ci 'def foo():\n' 8737db96d56Sopenharmony_ci ' collect()\n' 8747db96d56Sopenharmony_ci 'def bar():\n' 8757db96d56Sopenharmony_ci ' foo()\n' 8767db96d56Sopenharmony_ci 'bar()\n') 8777db96d56Sopenharmony_ci # Verify with "py-bt": 8787db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(cmd, 8797db96d56Sopenharmony_ci cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'], 8807db96d56Sopenharmony_ci ) 8817db96d56Sopenharmony_ci self.assertIn('Garbage-collecting', gdb_output) 8827db96d56Sopenharmony_ci 8837db96d56Sopenharmony_ci # Verify with "py-bt-full": 8847db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(cmd, 8857db96d56Sopenharmony_ci cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'], 8867db96d56Sopenharmony_ci ) 8877db96d56Sopenharmony_ci self.assertIn('Garbage-collecting', gdb_output) 8887db96d56Sopenharmony_ci 8897db96d56Sopenharmony_ci 8907db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 8917db96d56Sopenharmony_ci "Python was compiled with optimizations") 8927db96d56Sopenharmony_ci # Some older versions of gdb will fail with 8937db96d56Sopenharmony_ci # "Cannot find new threads: generic error" 8947db96d56Sopenharmony_ci # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround 8957db96d56Sopenharmony_ci # 8967db96d56Sopenharmony_ci # gdb will also generate many erroneous errors such as: 8977db96d56Sopenharmony_ci # Function "meth_varargs" not defined. 8987db96d56Sopenharmony_ci # This is because we are calling functions from an "external" module 8997db96d56Sopenharmony_ci # (_testcapimodule) rather than compiled-in functions. It seems difficult 9007db96d56Sopenharmony_ci # to suppress these. See also the comment in DebuggerTests.get_stack_trace 9017db96d56Sopenharmony_ci def test_pycfunction(self): 9027db96d56Sopenharmony_ci 'Verify that "py-bt" displays invocations of PyCFunction instances' 9037db96d56Sopenharmony_ci # bpo-46600: If the compiler inlines _null_to_none() in meth_varargs() 9047db96d56Sopenharmony_ci # (ex: clang -Og), _null_to_none() is the frame #1. Otherwise, 9057db96d56Sopenharmony_ci # meth_varargs() is the frame #1. 9067db96d56Sopenharmony_ci expected_frame = r'#(1|2)' 9077db96d56Sopenharmony_ci # Various optimizations multiply the code paths by which these are 9087db96d56Sopenharmony_ci # called, so test a variety of calling conventions. 9097db96d56Sopenharmony_ci for func_name, args in ( 9107db96d56Sopenharmony_ci ('meth_varargs', ''), 9117db96d56Sopenharmony_ci ('meth_varargs_keywords', ''), 9127db96d56Sopenharmony_ci ('meth_o', '[]'), 9137db96d56Sopenharmony_ci ('meth_noargs', ''), 9147db96d56Sopenharmony_ci ('meth_fastcall', ''), 9157db96d56Sopenharmony_ci ('meth_fastcall_keywords', ''), 9167db96d56Sopenharmony_ci ): 9177db96d56Sopenharmony_ci for obj in ( 9187db96d56Sopenharmony_ci '_testcapi', 9197db96d56Sopenharmony_ci '_testcapi.MethClass', 9207db96d56Sopenharmony_ci '_testcapi.MethClass()', 9217db96d56Sopenharmony_ci '_testcapi.MethStatic()', 9227db96d56Sopenharmony_ci 9237db96d56Sopenharmony_ci # XXX: bound methods don't yet give nice tracebacks 9247db96d56Sopenharmony_ci # '_testcapi.MethInstance()', 9257db96d56Sopenharmony_ci ): 9267db96d56Sopenharmony_ci with self.subTest(f'{obj}.{func_name}'): 9277db96d56Sopenharmony_ci cmd = textwrap.dedent(f''' 9287db96d56Sopenharmony_ci import _testcapi 9297db96d56Sopenharmony_ci def foo(): 9307db96d56Sopenharmony_ci {obj}.{func_name}({args}) 9317db96d56Sopenharmony_ci def bar(): 9327db96d56Sopenharmony_ci foo() 9337db96d56Sopenharmony_ci bar() 9347db96d56Sopenharmony_ci ''') 9357db96d56Sopenharmony_ci # Verify with "py-bt": 9367db96d56Sopenharmony_ci gdb_output = self.get_stack_trace( 9377db96d56Sopenharmony_ci cmd, 9387db96d56Sopenharmony_ci breakpoint=func_name, 9397db96d56Sopenharmony_ci cmds_after_breakpoint=['bt', 'py-bt'], 9407db96d56Sopenharmony_ci # bpo-45207: Ignore 'Function "meth_varargs" not 9417db96d56Sopenharmony_ci # defined.' message in stderr. 9427db96d56Sopenharmony_ci ignore_stderr=True, 9437db96d56Sopenharmony_ci ) 9447db96d56Sopenharmony_ci self.assertIn(f'<built-in method {func_name}', gdb_output) 9457db96d56Sopenharmony_ci 9467db96d56Sopenharmony_ci # Verify with "py-bt-full": 9477db96d56Sopenharmony_ci gdb_output = self.get_stack_trace( 9487db96d56Sopenharmony_ci cmd, 9497db96d56Sopenharmony_ci breakpoint=func_name, 9507db96d56Sopenharmony_ci cmds_after_breakpoint=['py-bt-full'], 9517db96d56Sopenharmony_ci # bpo-45207: Ignore 'Function "meth_varargs" not 9527db96d56Sopenharmony_ci # defined.' message in stderr. 9537db96d56Sopenharmony_ci ignore_stderr=True, 9547db96d56Sopenharmony_ci ) 9557db96d56Sopenharmony_ci regex = expected_frame 9567db96d56Sopenharmony_ci regex += re.escape(f' <built-in method {func_name}') 9577db96d56Sopenharmony_ci self.assertRegex(gdb_output, regex) 9587db96d56Sopenharmony_ci 9597db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 9607db96d56Sopenharmony_ci "Python was compiled with optimizations") 9617db96d56Sopenharmony_ci def test_wrapper_call(self): 9627db96d56Sopenharmony_ci cmd = textwrap.dedent(''' 9637db96d56Sopenharmony_ci class MyList(list): 9647db96d56Sopenharmony_ci def __init__(self): 9657db96d56Sopenharmony_ci super().__init__() # wrapper_call() 9667db96d56Sopenharmony_ci 9677db96d56Sopenharmony_ci id("first break point") 9687db96d56Sopenharmony_ci l = MyList() 9697db96d56Sopenharmony_ci ''') 9707db96d56Sopenharmony_ci cmds_after_breakpoint = ['break wrapper_call', 'continue'] 9717db96d56Sopenharmony_ci if CET_PROTECTION: 9727db96d56Sopenharmony_ci # bpo-32962: same case as in get_stack_trace(): 9737db96d56Sopenharmony_ci # we need an additional 'next' command in order to read 9747db96d56Sopenharmony_ci # arguments of the innermost function of the call stack. 9757db96d56Sopenharmony_ci cmds_after_breakpoint.append('next') 9767db96d56Sopenharmony_ci cmds_after_breakpoint.append('py-bt') 9777db96d56Sopenharmony_ci 9787db96d56Sopenharmony_ci # Verify with "py-bt": 9797db96d56Sopenharmony_ci gdb_output = self.get_stack_trace(cmd, 9807db96d56Sopenharmony_ci cmds_after_breakpoint=cmds_after_breakpoint) 9817db96d56Sopenharmony_ci self.assertRegex(gdb_output, 9827db96d56Sopenharmony_ci r"<method-wrapper u?'__init__' of MyList object at ") 9837db96d56Sopenharmony_ci 9847db96d56Sopenharmony_ciclass PyPrintTests(DebuggerTests): 9857db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 9867db96d56Sopenharmony_ci "Python was compiled with optimizations") 9877db96d56Sopenharmony_ci def test_basic_command(self): 9887db96d56Sopenharmony_ci 'Verify that the "py-print" command works' 9897db96d56Sopenharmony_ci bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, 9907db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-print args']) 9917db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 9927db96d56Sopenharmony_ci r".*\nlocal 'args' = \(1, 2, 3\)\n.*") 9937db96d56Sopenharmony_ci 9947db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 9957db96d56Sopenharmony_ci "Python was compiled with optimizations") 9967db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 9977db96d56Sopenharmony_ci def test_print_after_up(self): 9987db96d56Sopenharmony_ci bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, 9997db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a']) 10007db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 10017db96d56Sopenharmony_ci r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*") 10027db96d56Sopenharmony_ci 10037db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 10047db96d56Sopenharmony_ci "Python was compiled with optimizations") 10057db96d56Sopenharmony_ci def test_printing_global(self): 10067db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 10077db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-print __name__']) 10087db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 10097db96d56Sopenharmony_ci r".*\nglobal '__name__' = '__main__'\n.*") 10107db96d56Sopenharmony_ci 10117db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 10127db96d56Sopenharmony_ci "Python was compiled with optimizations") 10137db96d56Sopenharmony_ci def test_printing_builtin(self): 10147db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 10157db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-print len']) 10167db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 10177db96d56Sopenharmony_ci r".*\nbuiltin 'len' = <built-in method len of module object at remote 0x-?[0-9a-f]+>\n.*") 10187db96d56Sopenharmony_ci 10197db96d56Sopenharmony_ciclass PyLocalsTests(DebuggerTests): 10207db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 10217db96d56Sopenharmony_ci "Python was compiled with optimizations") 10227db96d56Sopenharmony_ci def test_basic_command(self): 10237db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 10247db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-locals']) 10257db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 10267db96d56Sopenharmony_ci r".*\nargs = \(1, 2, 3\)\n.*") 10277db96d56Sopenharmony_ci 10287db96d56Sopenharmony_ci @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") 10297db96d56Sopenharmony_ci @unittest.skipIf(python_is_optimized(), 10307db96d56Sopenharmony_ci "Python was compiled with optimizations") 10317db96d56Sopenharmony_ci def test_locals_after_up(self): 10327db96d56Sopenharmony_ci bt = self.get_stack_trace(script=self.get_sample_script(), 10337db96d56Sopenharmony_ci cmds_after_breakpoint=['py-up', 'py-up', 'py-locals']) 10347db96d56Sopenharmony_ci self.assertMultilineMatches(bt, 10357db96d56Sopenharmony_ci r'''^.* 10367db96d56Sopenharmony_ciLocals for foo 10377db96d56Sopenharmony_cia = 1 10387db96d56Sopenharmony_cib = 2 10397db96d56Sopenharmony_cic = 3 10407db96d56Sopenharmony_ciLocals for <module> 10417db96d56Sopenharmony_ci.*$''') 10427db96d56Sopenharmony_ci 10437db96d56Sopenharmony_ci 10447db96d56Sopenharmony_cidef setUpModule(): 10457db96d56Sopenharmony_ci if support.verbose: 10467db96d56Sopenharmony_ci print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version)) 10477db96d56Sopenharmony_ci for line in gdb_version.splitlines(): 10487db96d56Sopenharmony_ci print(" " * 4 + line) 10497db96d56Sopenharmony_ci 10507db96d56Sopenharmony_ci 10517db96d56Sopenharmony_ciif __name__ == "__main__": 10527db96d56Sopenharmony_ci unittest.main() 1053