#!/usr/bin/env python3 r""" This script launches gdbserver in a subprocess and waits until it's ready to receive a new connection since it's not possible to know if gdbserver is ready to connect to with `oodf` after executing it as a background task using `& !gdbserver ...`. Example usage in a test: !scripts/gdbserver.py --port PORT --binary bins/elf/analysis/calls_x64 It's important to note that PORT has to be unique for each test since all tests run in parallel and may attempt to open the same port at the same time. """ import argparse import os import subprocess def execute(cmd): with subprocess.Popen( cmd, stderr=subprocess.PIPE, universal_newlines=True ) as popen: for stderr_line in iter(popen.stderr.readline, ""): yield stderr_line def main(): parser = argparse.ArgumentParser( description="Run gdbserver in a new process with the given arguments and exit " "once gdbserver is ready for new connections" ) parser.add_argument("--host", default="127.0.0.1") parser.add_argument("--port", default="1234") parser.add_argument("--binary", default="") parser.add_argument( "--output", default=False, action="store_true", help="print stdout output from gdbserver", ) parser.add_argument( "--multi", default=False, action="store_true", help="start gdbserver in multi-process (extended-remote) mode", ) args = parser.parse_args() while True: cmd = ["gdbserver"] if args.multi: cmd.append("--multi") # --multi comes before HOST:PORT cmd.append(f"{args.host}:{args.port}") if args.binary: cmd.append(args.binary) for output in execute(cmd): if args.output: print(output) # Exit once gdbserver is ready for connections if "Listening on port" in output: os._exit(0) # pylint: disable=protected-access # gdbserver might fail to start if the port is taken if "Can't bind address" in output: print(output) os._exit(1) # pylint: disable=protected-access if __name__ == "__main__": main()