xref: /qemu/tests/guest-debug/run-test.py (revision 727385c4e13e1a5a985124a20a2370855141111d)
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 
14 import argparse
15 import subprocess
16 import shutil
17 import shlex
18 import os
19 from time import sleep
20 from tempfile import TemporaryDirectory
21 
22 def get_args():
23     parser = argparse.ArgumentParser(description="A gdbstub test runner")
24     parser.add_argument("--qemu", help="Qemu binary for test",
25                         required=True)
26     parser.add_argument("--qargs", help="Qemu arguments for test")
27     parser.add_argument("--binary", help="Binary to debug",
28                         required=True)
29     parser.add_argument("--test", help="GDB test script",
30                         required=True)
31     parser.add_argument("--gdb", help="The gdb binary to use",
32                         default=None)
33     parser.add_argument("--output", help="A file to redirect output to")
34 
35     return parser.parse_args()
36 
37 
38 def log(output, msg):
39     if output:
40         output.write(msg + "\n")
41         output.flush()
42     else:
43         print(msg)
44 
45 
46 if __name__ == '__main__':
47     args = get_args()
48 
49     # Search for a gdb we can use
50     if not args.gdb:
51         args.gdb = shutil.which("gdb-multiarch")
52     if not args.gdb:
53         args.gdb = shutil.which("gdb")
54     if not args.gdb:
55         print("We need gdb to run the test")
56         exit(-1)
57     if args.output:
58         output = open(args.output, "w")
59     else:
60         output = None
61 
62     socket_dir = TemporaryDirectory("qemu-gdbstub")
63     socket_name = os.path.join(socket_dir.name, "gdbstub.socket")
64 
65     # Launch QEMU with binary
66     if "system" in args.qemu:
67         cmd = "%s %s %s -gdb unix:path=%s,server=on" % (args.qemu,
68                                                         args.qargs,
69                                                         args.binary,
70                                                         socket_name)
71     else:
72         cmd = "%s %s -g %s %s" % (args.qemu, args.qargs, socket_name,
73                                   args.binary)
74 
75     log(output, "QEMU CMD: %s" % (cmd))
76     inferior = subprocess.Popen(shlex.split(cmd))
77 
78     # Now launch gdb with our test and collect the result
79     gdb_cmd = "%s %s" % (args.gdb, args.binary)
80     # run quietly and ignore .gdbinit
81     gdb_cmd += " -q -n -batch"
82     # disable prompts in case of crash
83     gdb_cmd += " -ex 'set confirm off'"
84     # connect to remote
85     gdb_cmd += " -ex 'target remote %s'" % (socket_name)
86     # finally the test script itself
87     gdb_cmd += " -x %s" % (args.test)
88 
89 
90     sleep(1)
91     log(output, "GDB CMD: %s" % (gdb_cmd))
92 
93     result = subprocess.call(gdb_cmd, shell=True, stdout=output)
94 
95     # A negative result is the result of an internal gdb failure like
96     # a crash. We force a return of 0 so we don't fail the test on
97     # account of broken external tools.
98     if result < 0:
99         print("GDB crashed? SKIPPING")
100         exit(0)
101 
102     try:
103         inferior.wait(2)
104     except subprocess.TimeoutExpired:
105         print("GDB never connected? Killed guest")
106         inferior.kill()
107 
108     exit(result)
109