extra/stack_analyzer: Support function sets in invalid paths.

There are lots of invalid paths have common segments.
In this patch, each vertex of an invalid path can be a function set.

Examples can be found in extra/stack_analyzer/example_annotation.yaml

BUG=chromium:648840
BRANCH=none
TEST=extra/stack_analyzer/stack_analyzer_unittest.py
     make BOARD=elm SECTION=RW \
         ANNOTATION=./extra/stack_analyzer/example_annotation.yaml \
         analyzestack

Change-Id: Ib10d68edd04725af4d803f54f7e208e55d574c7d
Signed-off-by: Che-yu Wu <cheyuw@google.com>
Reviewed-on: https://chromium-review.googlesource.com/649453
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
This commit is contained in:
Che-yu Wu
2017-09-05 11:05:26 +08:00
committed by chrome-bot
parent 848cf8f798
commit ce15362e89
3 changed files with 75 additions and 22 deletions

View File

@@ -24,6 +24,18 @@ remove:
# Remove some invalid paths.
- [pd_send_request_msg, set_state, pd_power_supply_reset]
- [__tx_char, __tx_char]
- [pd_send_request_msg, set_state, set_state]
- [pd_send_request_msg, set_state, set_state, pd_power_supply_reset]
- [set_state, set_state, set_state]
# Remove two invalid paths with the common prefix.
- [pd_execute_hard_reset, set_state, [charge_manager_update_dualrole, pd_dfp_exit_mode]]
# It is equivalent to the following two lines,
# - [pd_execute_hard_reset, set_state, charge_manager_update_dualrole]
# - [pd_execute_hard_reset, set_state, pd_dfp_exit_mode]
# Remove four invalid paths with the common segment.
- [[pd_send_request_msg, pd_request_vconn_swap], set_state, [usb_mux_set, pd_power_supply_reset]]
# It is equivalent to the following four lines,
# - [pd_send_request_msg, set_state, usb_mux_set]
# - [pd_send_request_msg, set_state, pd_power_supply_reset]
# - [pd_request_vconn_swap, set_state, usb_mux_set]
# - [pd_request_vconn_swap, set_state, pd_power_supply_reset]

View File

@@ -765,21 +765,49 @@ class StackAnalyzer(object):
add_rules[src_sig].add(dst_sig)
if 'remove' in self.annotation and self.annotation['remove'] is not None:
for remove_sigtxts in self.annotation['remove']:
if isinstance(remove_sigtxts, str):
remove_sigtxts = [remove_sigtxts]
for sigtxt_path in self.annotation['remove']:
if isinstance(sigtxt_path, str):
# The path has only one vertex.
sigtxt_path = [sigtxt_path]
remove_path = []
for remove_sigtxt in remove_sigtxts:
remove_sig = NormalizeSignature(remove_sigtxt)
if remove_sig is None:
invalid_sigtxts.add(remove_sigtxt)
if len(sigtxt_path) == 0:
continue
# Generate multiple remove paths from all the combinations of the
# signatures of each vertex.
sig_paths = [[]]
broken_flag = False
for sigtxt_node in sigtxt_path:
if isinstance(sigtxt_node, str):
# The vertex has only one signature.
sigtxt_set = {sigtxt_node}
elif isinstance(sigtxt_node, list):
# The vertex has multiple signatures.
sigtxt_set = set(sigtxt_node)
else:
remove_path.append(remove_sig)
# Assume the format of annotation is verified. There should be no
# invalid case.
assert False
if len(remove_path) == len(remove_sigtxts):
sig_set = set()
for sigtxt in sigtxt_set:
sig = NormalizeSignature(sigtxt)
if sig is None:
invalid_sigtxts.add(sigtxt)
broken_flag = True
elif not broken_flag:
sig_set.add(sig)
if broken_flag:
continue
# Append each signature of the current node to the all previous
# remove paths.
sig_paths = [path + [sig] for path in sig_paths for sig in sig_set]
if not broken_flag:
# All signatures are normalized. The remove path has no error.
remove_rules.append(remove_path)
remove_rules.extend(sig_paths)
return (add_rules, remove_rules, invalid_sigtxts)
@@ -897,21 +925,15 @@ class StackAnalyzer(object):
skip_flag = True
break
else:
paths = []
for remove_path in remove_paths:
# Append each function of the current signature to the all previous
# remove paths.
for remove_func in remove_funcs:
paths.append(remove_path + [remove_func])
remove_paths = paths
# Append each function of the current signature to the all previous
# remove paths.
remove_paths = [p + [f] for p in remove_paths for f in remove_funcs]
if skip_flag:
# Ignore the broken remove path.
continue
for remove_path in remove_paths:
skip_flag = False
# Deduplicate the remove paths.
if remove_path not in remove_list:
remove_list.append(remove_path)

View File

@@ -226,6 +226,25 @@ class StackAnalyzerTest(unittest.TestCase):
self.assertEqual(remove_rules, [])
self.assertEqual(invalid_sigtxts, set())
self.analyzer.annotation = {
'add': None,
'remove': [
[['a', 'b'], ['0', '[', '2'], 'x'],
[['a', 'b[x:3]'], ['0', '1', '2'], 'x'],
],
}
(add_rules, remove_rules, invalid_sigtxts) = self.analyzer.LoadAnnotation()
self.assertEqual(add_rules, {})
self.assertEqual(remove_rules, [
[('a', None, None), ('1', None, None), ('x', None, None)],
[('a', None, None), ('0', None, None), ('x', None, None)],
[('a', None, None), ('2', None, None), ('x', None, None)],
[('b', os.path.abspath('x'), 3), ('1', None, None), ('x', None, None)],
[('b', os.path.abspath('x'), 3), ('0', None, None), ('x', None, None)],
[('b', os.path.abspath('x'), 3), ('2', None, None), ('x', None, None)],
])
self.assertEqual(invalid_sigtxts, {'['})
funcs = {
0x1000: sa.Function(0x1000, 'hook_task', 0, []),
0x2000: sa.Function(0x2000, 'console_task', 0, []),