#!/usr/bin/env python3 # # Copyright (c) 2020 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 import argparse import logging import os import socket import sys from coredump_parser.log_parser import CoredumpLogFile from coredump_parser.elf_parser import CoredumpElfFile import gdbstubs LOGGING_FORMAT = "[%(levelname)s][%(name)s] %(message)s" # Only bind to local host GDBSERVER_HOST = "" class FakeSocket: def __init__(self) -> None: self.in_stream = sys.stdin.buffer self.out_stream = sys.stdout.buffer def recv(self, bufsize): return self.in_stream.read(bufsize) def send(self, data): n = self.out_stream.write(data) self.out_stream.flush() return n def close(self): pass def parse_args(): parser = argparse.ArgumentParser(allow_abbrev=False) parser.add_argument("elffile", help="Zephyr ELF binary") parser.add_argument("logfile", help="Coredump binary log file") parser.add_argument("--debug", action="store_true", help="Print extra debugging information") parser.add_argument("--port", type=int, default=1234, help="GDB server port") parser.add_argument("--pipe", action="store_true", help="Use stdio to communicate with gdb") parser.add_argument("-v", "--verbose", action="store_true", help="Print more information") return parser.parse_args() def main(): args = parse_args() # Setup logging logging.basicConfig(format=LOGGING_FORMAT) # Setup logging for "parser" logger = logging.getLogger("parser") if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) else: logger.setLevel(logging.WARNING) # Setup logging for follow code logger = logging.getLogger("gdbserver") if args.debug: logger.setLevel(logging.DEBUG) else: # Use INFO as default since we need to let user # know what is going on logger.setLevel(logging.INFO) # Setup logging for "gdbstub" logger = logging.getLogger("gdbstub") if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) else: logger.setLevel(logging.WARNING) if not os.path.isfile(args.elffile): logger.error(f"Cannot find file {args.elffile}, exiting...") sys.exit(1) if not os.path.isfile(args.logfile): logger.error(f"Cannot find file {args.logfile}, exiting...") sys.exit(1) logger.info(f"Log file: {args.logfile}") logger.info(f"ELF file: {args.elffile}") # Parse the coredump binary log file logf = CoredumpLogFile(args.logfile) logf.open() if not logf.parse(): logger.error("Cannot parse log file, exiting...") logf.close() sys.exit(1) # Parse ELF file for code and read-only data elff = CoredumpElfFile(args.elffile) elff.open() if not elff.parse(): logger.error("Cannot parse ELF file, exiting...") elff.close() logf.close() sys.exit(1) gdbstub = gdbstubs.get_gdbstub(logf, elff) if not args.pipe: # Start a GDB server gdbserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Reuse address so we don't have to wait for socket to be # close before we can bind to the port again gdbserver.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) gdbserver.bind((GDBSERVER_HOST, args.port)) gdbserver.listen(1) logger.info(f"Waiting GDB connection on port {args.port}...") conn, remote = gdbserver.accept() else: conn = FakeSocket() remote = "pipe" if conn: logger.info(f"Accepted GDB connection from {remote}") gdbstub.run(conn) conn.close() gdbserver.close() logger.info("GDB session finished.") elff.close() logf.close() if __name__ == "__main__": main()