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