summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYilin Yang <kerker@google.com>2020-09-21 14:55:55 +0800
committerCommit Bot <commit-bot@chromium.org>2020-09-25 09:48:17 +0000
commit4747bf170d58917025889fedc93e5a0ac7db7fb1 (patch)
tree38bfd006f6c1a75a767a8783f830156edfc0a79f
parent17cb616f9d7a0d4eabfcc3bd7a7f97ce36f4c834 (diff)
downloadchrome-ec-4747bf170d58917025889fedc93e5a0ac7db7fb1.tar.gz
stack_analyzer: Migrate to python3
BUG=chromium:1031705 BRANCH=master TEST=stack_analyzer_unittest.py TEST=`make BOARD=kukui SECTION=RO analyzestack` runs successfully Signed-off-by: kerker <kerker@chromium.org> Change-Id: I4027c9c21bdf5fb456430231f1e9bfefed3e8fdb Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2419737 Reviewed-by: Yu-Ping Wu <yupingso@chromium.org> Reviewed-by: Hung-Te Lin <hungte@chromium.org>
-rwxr-xr-xextra/stack_analyzer/run_tests.sh2
-rwxr-xr-xextra/stack_analyzer/stack_analyzer.py42
-rwxr-xr-xextra/stack_analyzer/stack_analyzer_unittest.py41
3 files changed, 47 insertions, 38 deletions
diff --git a/extra/stack_analyzer/run_tests.sh b/extra/stack_analyzer/run_tests.sh
index 0e307d8d4a..5662f60b8b 100755
--- a/extra/stack_analyzer/run_tests.sh
+++ b/extra/stack_analyzer/run_tests.sh
@@ -5,5 +5,5 @@
# found in the LICENSE file.
# Discover all the unit tests in extra/stack_analyzer directory and run them.
-python2 -m unittest discover -b -s extra/stack_analyzer -p *_unittest.py \
+python3 -m unittest discover -b -s extra/stack_analyzer -p "*_unittest.py" \
&& touch extra/stack_analyzer/.tests-passed
diff --git a/extra/stack_analyzer/stack_analyzer.py b/extra/stack_analyzer/stack_analyzer.py
index 1c6276f399..f455a50e23 100755
--- a/extra/stack_analyzer/stack_analyzer.py
+++ b/extra/stack_analyzer/stack_analyzer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -246,6 +246,9 @@ class Function(object):
return True
+ def __hash__(self):
+ return id(self)
+
class AndesAnalyzer(object):
"""Disassembly analyzer for Andes architecture.
@@ -275,8 +278,8 @@ class AndesAnalyzer(object):
PUSH_OPCODE_RE = re.compile(r'^push(\d{1,})$')
PUSH_OPERAND_RE = re.compile(r'^\$r\d{1,}, \#\d{1,} \! \{([^\]]+)\}')
SMW_OPCODE_RE = re.compile(r'^smw(\.\w\w|\.\w\w\w)$')
- SMW_OPERAND_RE = re.compile(r'^(\$r\d{1,}|\$\w\p), \[\$\w\p\], '
- r'(\$r\d{1,}|\$\w\p), \#\d\w\d \! \{([^\]]+)\}')
+ SMW_OPERAND_RE = re.compile(r'^(\$r\d{1,}|\$\wp), \[\$\wp\], '
+ r'(\$r\d{1,}|\$\wp), \#\d\w\d \! \{([^\]]+)\}')
OPERANDGROUP_RE = re.compile(r'^\$r\d{1,}\~\$r\d{1,}')
LWI_OPCODE_RE = re.compile(r'^lwi(\.\w\w)$')
@@ -369,8 +372,8 @@ class AndesAnalyzer(object):
if self.OPERANDGROUP_RE.match(operandgroup_text) is not None:
# capture number & transfer string to integer
oprandgrouphead = operandgroup_text.split(',')[0]
- rx=int(filter(str.isdigit, oprandgrouphead.split('~')[0]))
- ry=int(filter(str.isdigit, oprandgrouphead.split('~')[1]))
+ rx=int(''.join(filter(str.isdigit, oprandgrouphead.split('~')[0])))
+ ry=int(''.join(filter(str.isdigit, oprandgrouphead.split('~')[1])))
stack_frame += ((len(operandgroup_text.split(','))+ry-rx) *
self.GENERAL_PURPOSE_REGISTER_SIZE)
@@ -387,8 +390,8 @@ class AndesAnalyzer(object):
if self.OPERANDGROUP_RE.match(operandgroup_text) is not None:
# capture number & transfer string to integer
oprandgrouphead = operandgroup_text.split(',')[0]
- rx=int(filter(str.isdigit, oprandgrouphead.split('~')[0]))
- ry=int(filter(str.isdigit, oprandgrouphead.split('~')[1]))
+ rx=int(''.join(filter(str.isdigit, oprandgrouphead.split('~')[0])))
+ ry=int(''.join(filter(str.isdigit, oprandgrouphead.split('~')[1])))
stack_frame += ((len(operandgroup_text.split(','))+ry-rx) *
self.GENERAL_PURPOSE_REGISTER_SIZE)
@@ -616,7 +619,7 @@ class StackAnalyzer(object):
if resolve_inline:
args.append('-i')
- line_text = subprocess.check_output(args)
+ line_text = subprocess.check_output(args, encoding='utf-8')
except subprocess.CalledProcessError:
raise StackAnalyzerError('addr2line failed to resolve lines.')
except OSError:
@@ -656,9 +659,9 @@ class StackAnalyzer(object):
"""
disasm_lines = [line.strip() for line in disasm_text.splitlines()]
- if (disasm_lines[1].find("nds") != -1):
+ if 'nds' in disasm_lines[1]:
analyzer = AndesAnalyzer()
- elif (disasm_lines[1].find("arm") != -1):
+ elif 'arm' in disasm_lines[1]:
analyzer = ArmAnalyzer()
else:
raise StackAnalyzerError('Unsupported architecture.')
@@ -940,7 +943,7 @@ class StackAnalyzer(object):
# to symbol object.
for addr in range(begin_address+offset, end_address, stride):
# TODO(drinkcat): Not all architectures need to drop the first bit.
- val = self.rodata[(addr-self.rodata_offset)/4] & 0xfffffffe
+ val = self.rodata[(addr-self.rodata_offset) // 4] & 0xfffffffe
name = None
for symbol in self.symbols:
if (symbol.address == val):
@@ -1460,7 +1463,8 @@ class StackAnalyzer(object):
try:
disasm_text = subprocess.check_output([self.options.objdump,
'-d',
- self.options.elf_path])
+ self.options.elf_path],
+ encoding='utf-8')
except subprocess.CalledProcessError:
raise StackAnalyzerError('objdump failed to disassemble.')
except OSError:
@@ -1517,7 +1521,7 @@ class StackAnalyzer(object):
text_list.append(order_text)
- for _, text in sorted(text_list, key=lambda (k, _): k):
+ for _, text in sorted(text_list, key=lambda item: item[0]):
print(text)
print('Unresolved indirect callsites:')
@@ -1533,7 +1537,7 @@ class StackAnalyzer(object):
for address in indirect_callsites:
text_list.append(OutputInlineStack(address, ' '))
- for _, text in sorted(text_list, key=lambda (k, _): k):
+ for _, text in sorted(text_list, key=lambda item: item[0]):
print(text)
print('Unresolved annotation signatures:')
@@ -1674,7 +1678,9 @@ def LoadTasklist(section, export_taskinfo, symbols):
tasklist = []
for index in range(taskinfo_num):
taskinfo = taskinfos[index]
- tasklist.append(Task(taskinfo.name, taskinfo.routine, taskinfo.stack_size))
+ tasklist.append(Task(taskinfo.name.decode('utf-8'),
+ taskinfo.routine.decode('utf-8'),
+ taskinfo.stack_size))
# Resolve routine address for each task. It's more efficient to resolve all
# routine addresses of tasks together.
@@ -1729,11 +1735,13 @@ def main():
try:
symbol_text = subprocess.check_output([options.objdump,
'-t',
- options.elf_path])
+ options.elf_path],
+ encoding='utf-8')
rodata_text = subprocess.check_output([options.objdump,
'-s',
'-j', '.rodata',
- options.elf_path])
+ options.elf_path],
+ encoding='utf-8')
except subprocess.CalledProcessError:
raise StackAnalyzerError('objdump failed to dump symbol table or rodata.')
except OSError:
diff --git a/extra/stack_analyzer/stack_analyzer_unittest.py b/extra/stack_analyzer/stack_analyzer_unittest.py
index eb2f69b751..09753625c9 100755
--- a/extra/stack_analyzer/stack_analyzer_unittest.py
+++ b/extra/stack_analyzer/stack_analyzer_unittest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -197,8 +197,8 @@ class StackAnalyzerTest(unittest.TestCase):
def tasklist_to_taskinfos(pointer, tasklist):
taskinfos = []
for task in tasklist:
- taskinfos.append(sa.TaskInfo(name=task.name,
- routine=task.routine_name,
+ taskinfos.append(sa.TaskInfo(name=task.name.encode('utf-8'),
+ routine=task.routine_name.encode('utf-8'),
stack_size=task.stack_max_size))
TaskInfoArray = sa.TaskInfo * len(taskinfos)
@@ -598,28 +598,29 @@ class StackAnalyzerTest(unittest.TestCase):
self.assertEqual(self.analyzer.AddressToLine(0x1234),
[('fake_func', '/test.c', 1)])
checkoutput_mock.assert_called_once_with(
- ['addr2line', '-f', '-e', './ec.RW.elf', '1234'])
+ ['addr2line', '-f', '-e', './ec.RW.elf', '1234'], encoding='utf-8')
checkoutput_mock.reset_mock()
checkoutput_mock.return_value = 'fake_func\n/a.c:1\nbake_func\n/b.c:2\n'
self.assertEqual(self.analyzer.AddressToLine(0x1234, True),
[('fake_func', '/a.c', 1), ('bake_func', '/b.c', 2)])
checkoutput_mock.assert_called_once_with(
- ['addr2line', '-f', '-e', './ec.RW.elf', '1234', '-i'])
+ ['addr2line', '-f', '-e', './ec.RW.elf', '1234', '-i'],
+ encoding='utf-8')
checkoutput_mock.reset_mock()
checkoutput_mock.return_value = 'fake_func\n/test.c:1 (discriminator 128)'
self.assertEqual(self.analyzer.AddressToLine(0x12345),
[('fake_func', '/test.c', 1)])
checkoutput_mock.assert_called_once_with(
- ['addr2line', '-f', '-e', './ec.RW.elf', '12345'])
+ ['addr2line', '-f', '-e', './ec.RW.elf', '12345'], encoding='utf-8')
checkoutput_mock.reset_mock()
checkoutput_mock.return_value = '??\n:?\nbake_func\n/b.c:2\n'
self.assertEqual(self.analyzer.AddressToLine(0x123456),
[None, ('bake_func', '/b.c', 2)])
checkoutput_mock.assert_called_once_with(
- ['addr2line', '-f', '-e', './ec.RW.elf', '123456'])
+ ['addr2line', '-f', '-e', './ec.RW.elf', '123456'], encoding='utf-8')
checkoutput_mock.reset_mock()
with self.assertRaisesRegexp(sa.StackAnalyzerError,
@@ -660,7 +661,7 @@ class StackAnalyzerTest(unittest.TestCase):
'remove': [['fake_func']],
}
- with mock.patch('__builtin__.print') as print_mock:
+ with mock.patch('builtins.print') as print_mock:
checkoutput_mock.return_value = disasm_text
self.analyzer.Analyze()
print_mock.assert_has_calls([
@@ -719,7 +720,7 @@ class StackAnalyzerTest(unittest.TestCase):
'remove': [['fake_func']],
}
- with mock.patch('__builtin__.print') as print_mock:
+ with mock.patch('builtins.print') as print_mock:
checkoutput_mock.return_value = disasm_text
self.analyzer.Analyze()
print_mock.assert_has_calls([
@@ -771,31 +772,31 @@ class StackAnalyzerTest(unittest.TestCase):
with mock.patch('os.path.exists') as path_mock:
path_mock.return_value = False
- with mock.patch('__builtin__.print') as print_mock:
- with mock.patch('__builtin__.open', mock.mock_open()) as open_mock:
+ with mock.patch('builtins.print') as print_mock:
+ with mock.patch('builtins.open', mock.mock_open()) as open_mock:
sa.main()
print_mock.assert_any_call(
'Warning: Annotation file fake does not exist.')
with mock.patch('os.path.exists') as path_mock:
path_mock.return_value = True
- with mock.patch('__builtin__.print') as print_mock:
- with mock.patch('__builtin__.open', mock.mock_open()) as open_mock:
+ with mock.patch('builtins.print') as print_mock:
+ with mock.patch('builtins.open', mock.mock_open()) as open_mock:
open_mock.side_effect = IOError()
sa.main()
print_mock.assert_called_once_with(
'Error: Failed to open annotation file fake.')
- with mock.patch('__builtin__.print') as print_mock:
- with mock.patch('__builtin__.open', mock.mock_open()) as open_mock:
+ with mock.patch('builtins.print') as print_mock:
+ with mock.patch('builtins.open', mock.mock_open()) as open_mock:
open_mock.return_value.read.side_effect = ['{', '']
sa.main()
open_mock.assert_called_once_with('fake', 'r')
print_mock.assert_called_once_with(
'Error: Failed to parse annotation file fake.')
- with mock.patch('__builtin__.print') as print_mock:
- with mock.patch('__builtin__.open',
+ with mock.patch('builtins.print') as print_mock:
+ with mock.patch('builtins.open',
mock.mock_open(read_data='')) as open_mock:
sa.main()
print_mock.assert_called_once_with(
@@ -803,19 +804,19 @@ class StackAnalyzerTest(unittest.TestCase):
args.annotation = None
- with mock.patch('__builtin__.print') as print_mock:
+ with mock.patch('builtins.print') as print_mock:
checkoutput_mock.side_effect = [symbol_text, rodata_text]
sa.main()
print_mock.assert_called_once_with(
'Error: Failed to load export_taskinfo.')
- with mock.patch('__builtin__.print') as print_mock:
+ with mock.patch('builtins.print') as print_mock:
checkoutput_mock.side_effect = subprocess.CalledProcessError(1, '')
sa.main()
print_mock.assert_called_once_with(
'Error: objdump failed to dump symbol table or rodata.')
- with mock.patch('__builtin__.print') as print_mock:
+ with mock.patch('builtins.print') as print_mock:
checkoutput_mock.side_effect = OSError()
sa.main()
print_mock.assert_called_once_with('Error: Failed to run objdump.')