def premain() -> None: # If isatty() is false, we might be redirecting to a file (or in another non-interactive context) # If we're not being run interactivly, we shouldn't use terminal color codes # If inside GDB, isatty() may return false but we stil want colors if check_gdb() or (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): set_color_output(True) if check_gdb(): out_stream, err_stream = gdb_plugin.plugin.output_streams() else: out_stream = stream.Std(sys.stdout) err_stream = stream.Std(sys.stderr) main(out_stream, err_stream, sys.argv, input)
def parse_args(args): ''' Looks for the special -g and --gdb arguements Returns None if not found Returns an instance of Args if found, which can be passed to run_gdb() Returned Args has the arguments before and after the -g split ''' # debugging infinitaly nested debuggers isn't fun if check_gdb(): return None # Look for the -d or --gdb arguments, and split the argument list based on where they are for i in range(len(args)): if args[i] == '-g' or args[i] == '--gdb': return Args(args[:i], args[i + 1:]) elif len(args[i]) > 2 and args[i][0] == '-' and args[i][1] != '-': # look for a g at the end of a list of single char args if 'g' in args[i][:-1]: raise RuntimeError( repr(args[i]) + ' invalid, -g option must be last in a list of single-character options' ) if args[i][-1] == 'g': return Args(args[:i] + [args[i][:-1]], args[i + 1:]) return None
''' This backend runs wayland-debug as a GDB plugin This allows detection of multiple Wyland connections and GDB breakpoints on Wayland messages Note that when running as a GDB plugin, two instances of wayland-debug will be running - The instance started by the user, which runs GDB (the runner instance) - The instance insided GDB (the plugin instance) This module holds logic for both ''' from core.util import check_gdb from . import runner if check_gdb(): from .plugin import Plugin from .plugin import output_streams else: from .runner import run_gdb
def main(out_stream: stream.Base, err_stream: stream.Base, argv: List[str], input_func: Callable[[str], str]) -> None: ''' Parse arguments and run wayland-debug out_stream: An instance of stream.Base to use for output err_stream: An instance of stream.Base to use for logging and errors argv: A list of str arguments (should include the program name like sys.argv) input_func: the input builtin, or a mock function that behaves the same ''' # If we want to run inside GDB, the rest of main does not get called in this instance of the script # Instead GDB is run, an instance of wayland-debug is run inside it and main() is run in that # gdb_plugin.runner.parse_args() will check if this needs to happen, and gdb_plugin.run_gdb() will do it gdb_runner_args = gdb_plugin.runner.parse_args(argv) if gdb_runner_args: gdb_plugin.run_gdb(gdb_runner_args, False) return import argparse parser = argparse.ArgumentParser( description= 'Debug Wayland protocol messages, see https://github.com/wmww/wayland-debug for additional info' ) parser.add_argument('--matcher-help', action='store_true', help='show how to write matchers and exit') parser.add_argument( '-v', '--verbose', action='store_true', help='verbose output, mostly used for debugging this program') parser.add_argument('-l', '--load', dest='path', type=str, help='load WAYLAND_DEBUG=1 messages from a file') parser.add_argument( '-p', '--pipe', action='store_true', help= 'receive WAYLAND_DEBUG=1 messages from stdin (note: messages are printed to stderr so you may want to redirect using 2>&1 before piping)' ) parser.add_argument('-s', '--supress', action='store_true', help='supress non-wayland output of the program') parser.add_argument( '-c', '--color', action='store_true', help='force color output (default for interactive sessions)') parser.add_argument( '-C', '--no-color', action='store_true', help='disable color output (default for non-interactive sessions)') parser.add_argument( '-f', '--filter', dest='f', type=str, help='only show these objects/messages (see --matcher-help for syntax)' ) parser.add_argument( '-b', '--break', dest='b', type=str, help='stop on these objects/messages (see --matcher-help for syntax)') parser.add_argument( '-g', '--gdb', action='store_true', help= 'run inside gdb, all subsequent arguments are sent to gdb, when inside gdb start commands with \'wl\'' ) # NOTE: -g/--gdb is here only for the help text, it is processed without argparse in gdb_runner.main() args = parser.parse_args( args=argv[1:]) # chop off the first argument (program name) assert not args.gdb, 'GDB argument should have been intercepted by gdb_plugin.runner.parse_args()' if args.no_color: set_color_output(False) elif args.color: set_color_output(True) verbose = bool(args.verbose) unprocessed_output = not bool(args.supress) output = Output(verbose, unprocessed_output, out_stream, err_stream) if verbose: set_verbose(True) logger.info('Verbose output enabled') if args.no_color: if args.color: output.warn( 'Ignoring --color, since --no-color was also specified') logger.info('Color output disabled') elif args.color: # Print message in rainbow colors s = '' for i, c in enumerate('Color output enabled'): s += color('1;' + str(i % 6 + 31), c) logger.info(s) if unprocessed_output: logger.info('Showing unparsable output') if args.matcher_help: matcher.show_help(output) return filter_matcher = matcher.always if args.f: try: filter_matcher = matcher.parse(args.f).simplify() logger.info('Filter matcher: ' + str(filter_matcher)) except RuntimeError as e: output.error(e) stop_matcher = matcher.never if args.b: try: stop_matcher = matcher.parse(args.b).simplify() logger.info('Break matcher: ' + str(stop_matcher)) except RuntimeError as e: output.error(e) protocol.load_all(output) connection_list = ConnectionManager() ui_controller = Controller(output, connection_list, filter_matcher, stop_matcher) file_path = args.path input_from_pipe = args.pipe if check_gdb(): try: if file_path is not None or input_from_pipe: output.warn( 'Ignoring load/pipe argument because we\'re inside GDB') gdb_plugin.plugin.Plugin(output, connection_list, ui_controller, ui_controller) except: import traceback traceback.print_exc() elif file_path is not None: if input_from_pipe: output.warn('Ignoring piped input because load file is specified') file_input_main(file_path, output, connection_list, ui_controller, ui_controller, input_func) elif input_from_pipe: if args.b: output.warn( 'Ignoring stop matcher when stdin is used for messages') piped_input_main(output, connection_list) else: output.warn('No action specified') parser.print_help()
output.warn('Ignoring load file because we\'re inside GDB') gdb_plugin.plugin.Plugin(output, connection_list, ui_controller, ui_controller) except: import traceback traceback.print_exc() elif file_path: file_input_main(file_path, output, connection_list, ui_controller, ui_controller, input_func) else: if args.b: output.warn( 'Ignoring stop matcher when stdin is used for messages') piped_input_main(output, connection_list) if __name__ == '__main__': # If isatty() is false, we might be redirecting to a file (or in another non-interactive context) # If we're not being run interactivly, we shouldn't use terminal color codes # If inside GDB, isatty() may return false but we stil want colors if check_gdb() or (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): set_color_output(True) if check_gdb(): out_stream, err_stream = gdb_plugin.plugin.output_streams() else: out_stream = stream.Std(sys.stdout) err_stream = stream.Std(sys.stderr) main(out_stream, err_stream, sys.argv, input)