tiny-test-fw: support translate backtrace in IDFDUT

This commit is contained in:
He Yin Ling 2019-03-18 12:16:24 +08:00
parent ef82e8d0bc
commit 1b96cefaf8
3 changed files with 44 additions and 9 deletions

View file

@ -206,14 +206,15 @@ class RecvThread(threading.Thread):
CHECK_FUNCTIONS = [] CHECK_FUNCTIONS = []
""" DUT subclass can define a few check functions to process received data. """ """ 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__() super(RecvThread, self).__init__()
self.exit_event = threading.Event() self.exit_event = threading.Event()
self.setDaemon(True) self.setDaemon(True)
self.read = read self.read = read
self.data_cache = data_cache self.dut = dut
self.recorded_data = recorded_data self.data_cache = dut.data_cache
self.record_data_lock = record_data_lock self.recorded_data = dut.recorded_data
self.record_data_lock = dut.record_data_lock
self._line_cache = str() self._line_cache = str()
def _line_completion(self, data): def _line_completion(self, data):
@ -408,8 +409,7 @@ class BaseDUT(object):
:return: None :return: None
""" """
self._port_open() self._port_open()
self.receive_thread = self.RECV_THREAD_CLS(self._port_read, self.data_cache, self.receive_thread = self.RECV_THREAD_CLS(self._port_read, self)
self.recorded_data, self.record_data_lock)
self.receive_thread.start() self.receive_thread.start()
def close(self): def close(self):

View file

@ -32,6 +32,7 @@ class IDFApp(App.BaseApp):
super(IDFApp, self).__init__(app_path) super(IDFApp, self).__init__(app_path)
self.idf_path = self.get_sdk_path() self.idf_path = self.get_sdk_path()
self.binary_path = self.get_binary_path(app_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) assert os.path.exists(self.binary_path)
if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(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): if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
@ -102,6 +103,15 @@ class IDFApp(App.BaseApp):
""" """
pass 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 process_arg(self, arg): def process_arg(self, arg):
""" """
process args in download.config. convert to abs path for .bin args. strip spaces and CRLFs. process args in download.config. convert to abs path for .bin args. strip spaces and CRLFs.

View file

@ -20,6 +20,7 @@ import subprocess
import functools import functools
import random import random
import tempfile import tempfile
import subprocess
# python2 and python3 queue package name is different # python2 and python3 queue package name is different
try: try:
@ -50,9 +51,10 @@ class IDFRecvThread(DUT.RecvThread):
re.compile(r"(rst 0x\d+ \(TG\dWDT_SYS_RESET|TGWDT_CPU_RESET\))") 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_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): def __init__(self, read, dut):
super(IDFRecvThread, self).__init__(read, data_cache, recorded_data, record_data_lock) super(IDFRecvThread, self).__init__(read, dut)
self.exceptions = _queue.Queue() self.exceptions = _queue.Queue()
def collect_performance(self, comp_data): def collect_performance(self, comp_data):
@ -74,13 +76,23 @@ class IDFRecvThread(DUT.RecvThread):
break break
def detect_backtrace(self, comp_data): def detect_backtrace(self, comp_data):
# TODO: to support auto parse backtrace
start = 0 start = 0
while True: while True:
match = self.BACKTRACE_PATTERN.search(comp_data, pos=start) match = self.BACKTRACE_PATTERN.search(comp_data, pos=start)
if match: if match:
start = match.end() start = match.end()
Utility.console_log("[Backtrace]:{}".format(match.group(1)), color="red") 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: else:
break break
@ -108,6 +120,7 @@ class IDFDUT(DUT.SerialDUT):
# if need to erase NVS partition in start app # if need to erase NVS partition in start app
ERASE_NVS = True ERASE_NVS = True
RECV_THREAD_CLS = IDFRecvThread RECV_THREAD_CLS = IDFRecvThread
TOOLCHAIN_PREFIX = "xtensa-esp32-elf-"
def __init__(self, name, port, log_file, app, allow_dut_exception=False, **kwargs): def __init__(self, name, port, log_file, app, allow_dut_exception=False, **kwargs):
self.download_config, self.partition_table = app.process_app_info() self.download_config, self.partition_table = app.process_app_info()
@ -254,6 +267,17 @@ class IDFDUT(DUT.SerialDUT):
return ports 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 get_exceptions(self): def get_exceptions(self):
""" Get exceptions detected by DUT receive thread. """ """ Get exceptions detected by DUT receive thread. """
exceptions = [] exceptions = []
@ -268,4 +292,5 @@ class IDFDUT(DUT.SerialDUT):
def close(self): def close(self):
super(IDFDUT, self).close() super(IDFDUT, self).close()
if not self.allow_dut_exception and self.get_exceptions(): if not self.allow_dut_exception and self.get_exceptions():
Utility.console_log("DUT exception detected on {}".format(self), color="red")
raise IDFDUTException() raise IDFDUTException()