|
|
@@ -1,6 +1,7 @@
|
|
|
-# SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
|
|
+# SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
+import hashlib
|
|
|
import os
|
|
|
import queue # noqa: F401
|
|
|
import re
|
|
|
@@ -26,6 +27,14 @@ from .output_helpers import yellow_print
|
|
|
from .serial_reader import Reader
|
|
|
|
|
|
|
|
|
+def get_sha256(filename, block_size=65536): # type: (str, int) -> str
|
|
|
+ sha256 = hashlib.sha256()
|
|
|
+ with open(filename, 'rb') as f:
|
|
|
+ for block in iter(lambda: f.read(block_size), b''):
|
|
|
+ sha256.update(block)
|
|
|
+ return sha256.hexdigest()
|
|
|
+
|
|
|
+
|
|
|
def run_make(target, make, console, console_parser, event_queue, cmd_queue, logger):
|
|
|
# type: (str, str, miniterm.Console, ConsoleParser, queue.Queue, queue.Queue, Logger) -> None
|
|
|
if isinstance(make, list):
|
|
|
@@ -49,8 +58,8 @@ class SerialHandler:
|
|
|
The class is responsible for buffering serial input and performing corresponding commands.
|
|
|
"""
|
|
|
def __init__(self, last_line_part, serial_check_exit, logger, decode_panic, reading_panic, panic_buffer, target,
|
|
|
- force_line_print, start_cmd_sent, serial_instance, encrypted):
|
|
|
- # type: (bytes, bool, Logger, str, int, bytes,str, bool, bool, serial.Serial, bool) -> None
|
|
|
+ force_line_print, start_cmd_sent, serial_instance, encrypted, elf_file):
|
|
|
+ # type: (bytes, bool, Logger, str, int, bytes,str, bool, bool, serial.Serial, bool, str) -> None
|
|
|
self._last_line_part = last_line_part
|
|
|
self._serial_check_exit = serial_check_exit
|
|
|
self.logger = logger
|
|
|
@@ -62,6 +71,7 @@ class SerialHandler:
|
|
|
self.start_cmd_sent = start_cmd_sent
|
|
|
self.serial_instance = serial_instance
|
|
|
self.encrypted = encrypted
|
|
|
+ self.elf_file = elf_file
|
|
|
|
|
|
def handle_serial_input(self, data, console_parser, coredump, gdb_helper, line_matcher,
|
|
|
check_gdb_stub_and_run, finalize_line=False):
|
|
|
@@ -91,6 +101,7 @@ class SerialHandler:
|
|
|
with coredump.check(line):
|
|
|
if self._force_line_print or line_matcher.match(line.decode(errors='ignore')):
|
|
|
self.logger.print(line + b'\n')
|
|
|
+ self.compare_elf_sha256(line.decode(errors='ignore'))
|
|
|
self.logger.handle_possible_pc_address_in_line(line)
|
|
|
check_gdb_stub_and_run(line)
|
|
|
self._force_line_print = False
|
|
|
@@ -141,6 +152,24 @@ class SerialHandler:
|
|
|
gdb_helper.process_panic_output(self._panic_buffer, self.logger, self.target)
|
|
|
self._panic_buffer = b''
|
|
|
|
|
|
+ def compare_elf_sha256(self, line): # type: (str) -> None
|
|
|
+ elf_sha256_matcher = re.compile(
|
|
|
+ r'ELF file SHA256:\s+(?P<sha256_flashed>[a-z0-9]+)'
|
|
|
+ )
|
|
|
+ file_sha256_flashed_match = re.search(elf_sha256_matcher, line)
|
|
|
+ if not file_sha256_flashed_match:
|
|
|
+ return
|
|
|
+ file_sha256_flashed = file_sha256_flashed_match.group('sha256_flashed')
|
|
|
+ if not os.path.exists(self.elf_file):
|
|
|
+ yellow_print(f'ELF file not found. '
|
|
|
+ f"You need to build & flash the project before running 'monitor', "
|
|
|
+ f'and the binary on the device must match the one in the build directory exactly. ')
|
|
|
+ else:
|
|
|
+ file_sha256_build = get_sha256(self.elf_file)
|
|
|
+ if file_sha256_flashed not in f'{file_sha256_build}':
|
|
|
+ yellow_print(f'Warning: checksum mismatch between flashed and built applications. '
|
|
|
+ f'Checksum of built application is {file_sha256_build}')
|
|
|
+
|
|
|
def handle_commands(self, cmd, chip, run_make_func, console_reader, serial_reader):
|
|
|
# type: (int, str, Callable, ConsoleReader, Reader) -> None
|
|
|
config = get_chip_config(chip)
|
|
|
@@ -192,3 +221,44 @@ class SerialHandler:
|
|
|
self.serial_instance.setDTR(high) # IO0=HIGH, done
|
|
|
else:
|
|
|
raise RuntimeError('Bad command data %d' % cmd) # type: ignore
|
|
|
+
|
|
|
+
|
|
|
+class SerialHandlerNoElf(SerialHandler):
|
|
|
+ # This method avoids using 'gdb_helper,' 'coredump' and 'handle_possible_pc_address_in_line'
|
|
|
+ # where the elf file is required to be passed
|
|
|
+ def handle_serial_input(self, data, console_parser, coredump, gdb_helper, line_matcher,
|
|
|
+ check_gdb_stub_and_run, finalize_line=False):
|
|
|
+ # type: (bytes, ConsoleParser, CoreDump, Optional[GDBHelper], LineMatcher, Callable, bool) -> None
|
|
|
+
|
|
|
+ if self.start_cmd_sent:
|
|
|
+ self.start_cmd_sent = False
|
|
|
+ pos = data.find(b'+')
|
|
|
+ if pos != -1:
|
|
|
+ data = data[(pos + 1):]
|
|
|
+
|
|
|
+ sp = data.split(b'\n')
|
|
|
+ if self._last_line_part != b'':
|
|
|
+ # add unprocessed part from previous "data" to the first line
|
|
|
+ sp[0] = self._last_line_part + sp[0]
|
|
|
+ self._last_line_part = b''
|
|
|
+ if sp[-1] != b'':
|
|
|
+ # last part is not a full line
|
|
|
+ self._last_line_part = sp.pop()
|
|
|
+ for line in sp:
|
|
|
+ if line == b'':
|
|
|
+ continue
|
|
|
+ if self._serial_check_exit and line == console_parser.exit_key.encode('latin-1'):
|
|
|
+ raise SerialStopException()
|
|
|
+
|
|
|
+ self.logger.print(line + b'\n')
|
|
|
+ self.compare_elf_sha256(line.decode(errors='ignore'))
|
|
|
+ self._force_line_print = False
|
|
|
+
|
|
|
+ force_print_or_matched = any((
|
|
|
+ self._force_line_print,
|
|
|
+ (finalize_line and line_matcher.match(self._last_line_part.decode(errors='ignore')))
|
|
|
+ ))
|
|
|
+
|
|
|
+ if self._last_line_part != b'' and force_print_or_matched:
|
|
|
+ self._force_line_print = True
|
|
|
+ self.logger.print(self._last_line_part)
|