/Lib/test/test_jit_gdb.py

http://unladen-swallow.googlecode.com/ · Python · 79 lines · 50 code · 14 blank · 15 comment · 6 complexity · 2c183d083ed6fc1600de4661c554cbc8 MD5 · raw file

  1. # Test that gdb can debug JITted Python code.
  2. import os
  3. import re
  4. import subprocess
  5. import sys
  6. import unittest
  7. from test.test_support import run_unittest, TestSkipped
  8. try:
  9. import _llvm
  10. except ImportError:
  11. raise TestSkipped("Built without JIT support")
  12. try:
  13. gdb_version, _ = subprocess.Popen(["gdb", "--version"],
  14. stdout=subprocess.PIPE).communicate()
  15. except OSError:
  16. # This is what "no gdb" looks like. There may, however, be other
  17. # errors that manifest this way too.
  18. raise TestSkipped("Couldn't find gdb on the path")
  19. gdb_version_number = re.search(r"^GNU gdb [^\d]*(\d+)\.", gdb_version)
  20. if int(gdb_version_number.group(1)) < 7:
  21. raise TestSkipped("gdb versions before 7.0 didn't support JIT debugging."
  22. " Saw:\n" + gdb_version)
  23. class DebuggerTests(unittest.TestCase):
  24. """Test that the debugger can debug Python."""
  25. def run_gdb(self, *args):
  26. """Runs gdb with the command line given by *args. Returns its stdout.
  27. Forwards stderr to the current process's stderr.
  28. """
  29. # err winds up empty.
  30. out, err = subprocess.Popen(
  31. args, stdout=subprocess.PIPE,
  32. stderr=None, # Forward stderr to the current process's stderr.
  33. env=dict(PYTHONLLVMFLAGS="-jit-emit-debug", **os.environ)
  34. ).communicate()
  35. return out
  36. def test_gets_stack_trace(self):
  37. gdb_output = self.run_gdb("gdb", "--batch",
  38. # Use 'start' to load any shared libraries.
  39. "--eval-command=start",
  40. "--eval-command=break PyObject_Print",
  41. "--eval-command=run",
  42. "--eval-command=backtrace",
  43. "--eval-command=continue",
  44. "--args",
  45. sys.executable, "-S", "-c", """
  46. def foo(): bar()
  47. def bar(): baz()
  48. def baz(): print 'Hello, World!'
  49. for function in (foo, bar, baz):
  50. function.__code__.co_use_jit = True
  51. foo()""")
  52. # Get the indices of each function in the stack trace.
  53. foo, bar, baz, output = map(
  54. gdb_output.find, ("_23_foo", "_23_bar",
  55. "_23_baz", "Hello, World!"))
  56. # str.find returns -1 on failure, so this makes sure each
  57. # string is in the output.
  58. self.assertTrue(-1 not in (foo, bar, baz, output), msg=gdb_output)
  59. # And now we make sure they're in the right order in the backtrace.
  60. self.assertTrue(baz < bar < foo < output, msg=gdb_output)
  61. def test_main():
  62. run_unittest(DebuggerTests)
  63. if __name__ == "__main__":
  64. test_main()