2
0

run-test.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/env python3
  2. #
  3. # Run a gdbstub test case
  4. #
  5. # Copyright (c) 2019 Linaro
  6. #
  7. # Author: Alex Bennée <alex.bennee@linaro.org>
  8. #
  9. # This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. # See the COPYING file in the top-level directory.
  11. #
  12. # SPDX-License-Identifier: GPL-2.0-or-later
  13. import argparse
  14. import subprocess
  15. import shutil
  16. import shlex
  17. import os
  18. from time import sleep
  19. from tempfile import TemporaryDirectory
  20. def get_args():
  21. parser = argparse.ArgumentParser(description="A gdbstub test runner")
  22. parser.add_argument("--qemu", help="Qemu binary for test",
  23. required=True)
  24. parser.add_argument("--qargs", help="Qemu arguments for test")
  25. parser.add_argument("--binary", help="Binary to debug",
  26. required=True)
  27. parser.add_argument("--test", help="GDB test script")
  28. parser.add_argument('test_args', nargs='*',
  29. help="Additional args for GDB test script. "
  30. "The args should be preceded by -- to avoid confusion "
  31. "with flags for runner script")
  32. parser.add_argument("--gdb", help="The gdb binary to use",
  33. default=None)
  34. parser.add_argument("--gdb-args", help="Additional gdb arguments")
  35. parser.add_argument("--output", help="A file to redirect output to")
  36. parser.add_argument("--stderr", help="A file to redirect stderr to")
  37. parser.add_argument("--no-suspend", action="store_true",
  38. help="Ask the binary to not wait for GDB connection")
  39. return parser.parse_args()
  40. def log(output, msg):
  41. if output:
  42. output.write(msg + "\n")
  43. output.flush()
  44. else:
  45. print(msg)
  46. if __name__ == '__main__':
  47. args = get_args()
  48. # Search for a gdb we can use
  49. if not args.gdb:
  50. args.gdb = shutil.which("gdb-multiarch")
  51. if not args.gdb:
  52. args.gdb = shutil.which("gdb")
  53. if not args.gdb:
  54. print("We need gdb to run the test")
  55. exit(-1)
  56. if args.output:
  57. output = open(args.output, "w")
  58. else:
  59. output = None
  60. if args.stderr:
  61. stderr = open(args.stderr, "w")
  62. else:
  63. stderr = None
  64. socket_dir = TemporaryDirectory("qemu-gdbstub")
  65. socket_name = os.path.join(socket_dir.name, "gdbstub.socket")
  66. # Launch QEMU with binary
  67. if "system" in args.qemu:
  68. if args.no_suspend:
  69. suspend = ''
  70. else:
  71. suspend = ' -S'
  72. cmd = f'{args.qemu} {args.qargs} {args.binary}' \
  73. f'{suspend} -gdb unix:path={socket_name},server=on'
  74. else:
  75. if args.no_suspend:
  76. suspend = ',suspend=n'
  77. else:
  78. suspend = ''
  79. cmd = f'{args.qemu} {args.qargs} -g {socket_name}{suspend}' \
  80. f' {args.binary}'
  81. log(output, "QEMU CMD: %s" % (cmd))
  82. inferior = subprocess.Popen(shlex.split(cmd))
  83. # Now launch gdb with our test and collect the result
  84. gdb_cmd = "%s %s" % (args.gdb, args.binary)
  85. if args.gdb_args:
  86. gdb_cmd += " %s" % (args.gdb_args)
  87. # run quietly and ignore .gdbinit
  88. gdb_cmd += " -q -n -batch"
  89. # disable pagination
  90. gdb_cmd += " -ex 'set pagination off'"
  91. # disable prompts in case of crash
  92. gdb_cmd += " -ex 'set confirm off'"
  93. # connect to remote
  94. gdb_cmd += " -ex 'target remote %s'" % (socket_name)
  95. # finally the test script itself
  96. if args.test:
  97. if args.test_args:
  98. gdb_cmd += f" -ex \"py sys.argv={args.test_args}\""
  99. gdb_cmd += " -x %s" % (args.test)
  100. sleep(1)
  101. log(output, "GDB CMD: %s" % (gdb_cmd))
  102. gdb_env = dict(os.environ)
  103. gdb_pythonpath = gdb_env.get("PYTHONPATH", "").split(os.pathsep)
  104. gdb_pythonpath.append(os.path.dirname(os.path.realpath(__file__)))
  105. gdb_env["PYTHONPATH"] = os.pathsep.join(gdb_pythonpath)
  106. result = subprocess.call(gdb_cmd, shell=True, stdout=output, stderr=stderr,
  107. env=gdb_env)
  108. # A result of greater than 128 indicates a fatal signal (likely a
  109. # crash due to gdb internal failure). That's a problem for GDB and
  110. # not the test so we force a return of 0 so we don't fail the test on
  111. # account of broken external tools.
  112. if result > 128:
  113. log(output, "GDB crashed? (%d, %d) SKIPPING" % (result, result - 128))
  114. exit(0)
  115. try:
  116. inferior.wait(2)
  117. except subprocess.TimeoutExpired:
  118. log(output, "GDB never connected? Killed guest")
  119. inferior.kill()
  120. exit(result)