mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
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:
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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, []),
|
||||
|
||||
Reference in New Issue
Block a user