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