1#!/usr/bin/env python3 2# 3# Copyright (c) 2020 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import argparse 8import logging 9import os 10import socket 11import sys 12 13import gdbstubs 14from coredump_parser.elf_parser import CoredumpElfFile 15from coredump_parser.log_parser import CoredumpLogFile 16 17LOGGING_FORMAT = "[%(levelname)s][%(name)s] %(message)s" 18 19# Only bind to local host 20GDBSERVER_HOST = "" 21 22 23class FakeSocket: 24 def __init__(self) -> None: 25 self.in_stream = sys.stdin.buffer 26 self.out_stream = sys.stdout.buffer 27 28 def recv(self, bufsize): 29 return self.in_stream.read(bufsize) 30 31 def send(self, data): 32 n = self.out_stream.write(data) 33 self.out_stream.flush() 34 return n 35 36 def close(self): 37 pass 38 39 40def parse_args(): 41 parser = argparse.ArgumentParser(allow_abbrev=False) 42 43 parser.add_argument("elffile", help="Zephyr ELF binary") 44 parser.add_argument("logfile", help="Coredump binary log file") 45 parser.add_argument("--debug", action="store_true", help="Print extra debugging information") 46 parser.add_argument("--port", type=int, default=1234, help="GDB server port") 47 parser.add_argument("--pipe", action="store_true", help="Use stdio to communicate with gdb") 48 parser.add_argument("-v", "--verbose", action="store_true", help="Print more information") 49 50 return parser.parse_args() 51 52 53def main(): 54 args = parse_args() 55 56 # Setup logging 57 logging.basicConfig(format=LOGGING_FORMAT) 58 59 # Setup logging for "parser" 60 logger = logging.getLogger("parser") 61 if args.debug: 62 logger.setLevel(logging.DEBUG) 63 elif args.verbose: 64 logger.setLevel(logging.INFO) 65 else: 66 logger.setLevel(logging.WARNING) 67 68 # Setup logging for follow code 69 logger = logging.getLogger("gdbserver") 70 if args.debug: 71 logger.setLevel(logging.DEBUG) 72 else: 73 # Use INFO as default since we need to let user 74 # know what is going on 75 logger.setLevel(logging.INFO) 76 77 # Setup logging for "gdbstub" 78 logger = logging.getLogger("gdbstub") 79 if args.debug: 80 logger.setLevel(logging.DEBUG) 81 elif args.verbose: 82 logger.setLevel(logging.INFO) 83 else: 84 logger.setLevel(logging.WARNING) 85 86 if not os.path.isfile(args.elffile): 87 logger.error(f"Cannot find file {args.elffile}, exiting...") 88 sys.exit(1) 89 90 if not os.path.isfile(args.logfile): 91 logger.error(f"Cannot find file {args.logfile}, exiting...") 92 sys.exit(1) 93 94 logger.info(f"Log file: {args.logfile}") 95 logger.info(f"ELF file: {args.elffile}") 96 97 # Parse the coredump binary log file 98 logf = CoredumpLogFile(args.logfile) 99 logf.open() 100 if not logf.parse(): 101 logger.error("Cannot parse log file, exiting...") 102 logf.close() 103 sys.exit(1) 104 105 # Parse ELF file for code and read-only data 106 elff = CoredumpElfFile(args.elffile) 107 elff.open() 108 if not elff.parse(): 109 logger.error("Cannot parse ELF file, exiting...") 110 elff.close() 111 logf.close() 112 sys.exit(1) 113 114 gdbstub = gdbstubs.get_gdbstub(logf, elff) 115 116 if not args.pipe: 117 # Start a GDB server 118 gdbserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 119 120 # Reuse address so we don't have to wait for socket to be 121 # close before we can bind to the port again 122 gdbserver.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 123 124 gdbserver.bind((GDBSERVER_HOST, args.port)) 125 gdbserver.listen(1) 126 127 logger.info(f"Waiting GDB connection on port {args.port}...") 128 129 conn, remote = gdbserver.accept() 130 else: 131 conn = FakeSocket() 132 remote = "pipe" 133 134 if conn: 135 logger.info(f"Accepted GDB connection from {remote}") 136 137 gdbstub.run(conn) 138 139 conn.close() 140 141 gdbserver.close() 142 143 logger.info("GDB session finished.") 144 145 elff.close() 146 logf.close() 147 148 149if __name__ == "__main__": 150 main() 151