From 31c8be0738c385d9c9117738fbe18ad38ddf24c5 Mon Sep 17 00:00:00 2001 From: He Yin Ling Date: Mon, 18 Mar 2019 12:16:24 +0800 Subject: [PATCH] tiny-test-fw: support translate backtrace in IDFDUT --- tools/tiny-test-fw/DUT.py | 12 ++++++------ tools/tiny-test-fw/IDF/IDFApp.py | 10 ++++++++++ tools/tiny-test-fw/IDF/IDFDUT.py | 32 ++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/tools/tiny-test-fw/DUT.py b/tools/tiny-test-fw/DUT.py index 0c6ee29e9..34ac28578 100644 --- a/tools/tiny-test-fw/DUT.py +++ b/tools/tiny-test-fw/DUT.py @@ -206,14 +206,15 @@ class RecvThread(threading.Thread): CHECK_FUNCTIONS = [] """ DUT subclass can define a few check functions to process received data. """ - def __init__(self, read, data_cache, recorded_data, record_data_lock): + def __init__(self, read, dut): super(RecvThread, self).__init__() self.exit_event = threading.Event() self.setDaemon(True) self.read = read - self.data_cache = data_cache - self.recorded_data = recorded_data - self.record_data_lock = record_data_lock + self.dut = dut + self.data_cache = dut.data_cache + self.recorded_data = dut.recorded_data + self.record_data_lock = dut.record_data_lock self._line_cache = str() def _line_completion(self, data): @@ -407,8 +408,7 @@ class BaseDUT(object): :return: None """ - self.receive_thread = self.RECV_THREAD_CLS(self._port_read, self.data_cache, - self.recorded_data, self.record_data_lock) + self.receive_thread = self.RECV_THREAD_CLS(self._port_read, self) self.receive_thread.start() def stop_receive(self): diff --git a/tools/tiny-test-fw/IDF/IDFApp.py b/tools/tiny-test-fw/IDF/IDFApp.py index 4257588fa..45386f0eb 100644 --- a/tools/tiny-test-fw/IDF/IDFApp.py +++ b/tools/tiny-test-fw/IDF/IDFApp.py @@ -33,6 +33,7 @@ class IDFApp(App.BaseApp): super(IDFApp, self).__init__(app_path) self.idf_path = self.get_sdk_path() self.binary_path = self.get_binary_path(app_path) + self.elf_file = self._get_elf_file_path(self.binary_path) assert os.path.exists(self.binary_path) if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path): if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path): @@ -94,6 +95,15 @@ class IDFApp(App.BaseApp): """ pass + @staticmethod + def _get_elf_file_path(binary_path): + ret = "" + file_names = os.listdir(binary_path) + for fn in file_names: + if os.path.splitext(fn)[1] == ".elf": + ret = os.path.join(binary_path, fn) + return ret + def _parse_flash_download_config(self): """ Parse flash download config from build metadata files diff --git a/tools/tiny-test-fw/IDF/IDFDUT.py b/tools/tiny-test-fw/IDF/IDFDUT.py index 73314979b..e949f7ca3 100644 --- a/tools/tiny-test-fw/IDF/IDFDUT.py +++ b/tools/tiny-test-fw/IDF/IDFDUT.py @@ -19,6 +19,7 @@ import sys import re import functools import tempfile +import subprocess # python2 and python3 queue package name is different try: @@ -59,9 +60,10 @@ class IDFRecvThread(DUT.RecvThread): re.compile(r"(rst 0x\d+ \(TG\dWDT_SYS_RESET|TGWDT_CPU_RESET\))") ] BACKTRACE_PATTERN = re.compile(r"Backtrace:((\s(0x[0-9a-f]{8}):0x[0-9a-f]{8})+)") + BACKTRACE_ADDRESS_PATTERN = re.compile(r"(0x[0-9a-f]{8}):0x[0-9a-f]{8}") - def __init__(self, read, data_cache, recorded_data, record_data_lock): - super(IDFRecvThread, self).__init__(read, data_cache, recorded_data, record_data_lock) + def __init__(self, read, dut): + super(IDFRecvThread, self).__init__(read, dut) self.exceptions = _queue.Queue() def collect_performance(self, comp_data): @@ -83,13 +85,23 @@ class IDFRecvThread(DUT.RecvThread): break def detect_backtrace(self, comp_data): - # TODO: to support auto parse backtrace start = 0 while True: match = self.BACKTRACE_PATTERN.search(comp_data, pos=start) if match: start = match.end() Utility.console_log("[Backtrace]:{}".format(match.group(1)), color="red") + # translate backtrace + addresses = self.BACKTRACE_ADDRESS_PATTERN.findall(match.group(1)) + translated_backtrace = "" + for addr in addresses: + ret = self.dut.lookup_pc_address(addr) + if ret: + translated_backtrace += ret + "\n" + if translated_backtrace: + Utility.console_log("Translated backtrace\n:" + translated_backtrace, color="yellow") + else: + Utility.console_log("Failed to translate backtrace", color="yellow") else: break @@ -137,9 +149,9 @@ class IDFDUT(DUT.SerialDUT): # if need to erase NVS partition in start app ERASE_NVS = True RECV_THREAD_CLS = IDFRecvThread + TOOLCHAIN_PREFIX = "xtensa-esp32-elf-" def __init__(self, name, port, log_file, app, allow_dut_exception=False, **kwargs): - self.download_config, self.partition_table = app.process_app_info() super(IDFDUT, self).__init__(name, port, log_file, app, **kwargs) self.allow_dut_exception = allow_dut_exception self.exceptions = _queue.Queue() @@ -315,6 +327,17 @@ class IDFDUT(DUT.SerialDUT): return ports + def lookup_pc_address(self, pc_addr): + cmd = ["%saddr2line" % self.TOOLCHAIN_PREFIX, + "-pfiaC", "-e", self.app.elf_file, pc_addr] + ret = "" + try: + translation = subprocess.check_output(cmd) + ret = translation.decode() + except OSError: + pass + return ret + def stop_receive(self): if self.receive_thread: while True: @@ -343,4 +366,5 @@ class IDFDUT(DUT.SerialDUT): def close(self): super(IDFDUT, self).close() if not self.allow_dut_exception and self.get_exceptions(): + Utility.console_log("DUT exception detected on {}".format(self), color="red") raise IDFDUTException()