twister: fix Ztest C++ test names extraction from ELF
Fix Ztest test function name extraction from ELF symbols for C++ compiled binaries where symbol names need additional 'demangling' to match with corresponding test names. The `c++filt` utility (part of binutils) is called for demangling when it is needed. Twister test suite extension and adjustment. Signed-off-by: Dmitrii Golovanov <dmitrii.golovanov@intel.com>
This commit is contained in:
parent
18451bca44
commit
e11aecaed5
21 changed files with 288 additions and 35 deletions
|
@ -814,6 +814,10 @@ class ProjectBuilder(FilterBuilder):
|
|||
self.env = env
|
||||
self.duts = None
|
||||
|
||||
@property
|
||||
def trace(self) -> bool:
|
||||
return self.options.verbose > 2
|
||||
|
||||
def log_info(self, filename, inline_logs, log_testcases=False):
|
||||
filename = os.path.abspath(os.path.realpath(filename))
|
||||
if inline_logs:
|
||||
|
@ -1087,6 +1091,18 @@ class ProjectBuilder(FilterBuilder):
|
|||
self.instance.reason = reason
|
||||
self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason)
|
||||
|
||||
def demangle(self, symbol_name):
|
||||
if symbol_name[:2] == '_Z':
|
||||
try:
|
||||
cpp_filt = subprocess.run('c++filt', input=symbol_name, text=True, check=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if self.trace:
|
||||
logger.debug(f"Demangle: '{symbol_name}'==>'{cpp_filt.stdout}'")
|
||||
return cpp_filt.stdout.strip()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to demangle '{symbol_name}': {e}")
|
||||
return symbol_name
|
||||
|
||||
def determine_testcases(self, results):
|
||||
yaml_testsuite_name = self.instance.testsuite.id
|
||||
logger.debug(f"Determine test cases for test suite: {yaml_testsuite_name}")
|
||||
|
@ -1102,19 +1118,22 @@ class ProjectBuilder(FilterBuilder):
|
|||
for sym in section.iter_symbols():
|
||||
# It is only meant for new ztest fx because only new ztest fx exposes test functions
|
||||
# precisely.
|
||||
|
||||
m_ = new_ztest_unit_test_regex.search(sym.name)
|
||||
if not m_:
|
||||
continue
|
||||
# Demangle C++ symbols
|
||||
m_ = new_ztest_unit_test_regex.search(self.demangle(sym.name))
|
||||
if not m_:
|
||||
continue
|
||||
# The 1st capture group is new ztest suite name.
|
||||
# The 2nd capture group is new ztest unit test name.
|
||||
matches = new_ztest_unit_test_regex.findall(sym.name)
|
||||
if matches:
|
||||
for m in matches:
|
||||
new_ztest_suite = m[0]
|
||||
if new_ztest_suite not in self.instance.testsuite.ztest_suite_names:
|
||||
logger.warning(f"Unexpected Ztest suite '{new_ztest_suite}' "
|
||||
f"not present in: {self.instance.testsuite.ztest_suite_names}")
|
||||
test_func_name = m[1].replace("test_", "", 1)
|
||||
testcase_id = f"{yaml_testsuite_name}.{new_ztest_suite}.{test_func_name}"
|
||||
detected_cases.append(testcase_id)
|
||||
new_ztest_suite = m_[1]
|
||||
if new_ztest_suite not in self.instance.testsuite.ztest_suite_names:
|
||||
logger.warning(f"Unexpected Ztest suite '{new_ztest_suite}' "
|
||||
f"not present in: {self.instance.testsuite.ztest_suite_names}")
|
||||
test_func_name = m_[2].replace("test_", "", 1)
|
||||
testcase_id = f"{yaml_testsuite_name}.{new_ztest_suite}.{test_func_name}"
|
||||
detected_cases.append(testcase_id)
|
||||
|
||||
if detected_cases:
|
||||
logger.debug(f"Detected Ztest cases: [{', '.join(detected_cases)}] in {elf_file}")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue