From 4b490cbb31aa9cb817864cf525fce21bf2943c41 Mon Sep 17 00:00:00 2001 From: tim Date: Mon, 20 Aug 2018 13:49:17 +0800 Subject: stack_analyzer_unittest: Unit test of analyze disassembly for Andes instruction Write a rough disassembly with Andes instruction in stack_analyzer_unittest.py which rough disassembly is analyzed by stack_analyzer.py to get some results. If these results are the same with expect results, the unit test will pass. In the rough disassembly, the file format is added in the second line, because the stack analyzer will be looking for the word of 'arm' or 'nds' in the line, and then get the corresponding Analyzer class. BUG=b:111746842 BRANCH=none TEST=./extra/stack_analyzer/run_tests.sh Change-Id: I3acbfb199f762a4e89ea95f6254628871a5beb5d Signed-off-by: tim Reviewed-on: https://chromium-review.googlesource.com/1174331 Commit-Ready: Tim2 Lin Tested-by: Tim2 Lin Reviewed-by: Randall Spangler Reviewed-by: Jett Rink Reviewed-by: Nicolas Boichat --- extra/stack_analyzer/stack_analyzer_unittest.py | 102 +++++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/extra/stack_analyzer/stack_analyzer_unittest.py b/extra/stack_analyzer/stack_analyzer_unittest.py index d159b2e14a..eb2f69b751 100755 --- a/extra/stack_analyzer/stack_analyzer_unittest.py +++ b/extra/stack_analyzer/stack_analyzer_unittest.py @@ -424,8 +424,45 @@ class StackAnalyzerTest(unittest.TestCase): [funcs[0x2000], funcs[0x4000], funcs[0x2000]], ]) - def testAnalyzeDisassembly(self): + def testAndesAnalyzeDisassembly(self): disasm_text = ( + '\n' + 'build/{BOARD}/RW/ec.RW.elf: file format elf32-nds32le' + '\n' + 'Disassembly of section .text:\n' + '\n' + '00000900 :\n' + ' ...\n' + '00001000 :\n' + ' 1000: fc 42\tpush25 $r10, #16 ! {$r6~$r10, $fp, $gp, $lp}\n' + ' 1004: 47 70\t\tmovi55 $r0, #1\n' + ' 1006: b1 13\tbnezs8 100929de \n' + ' 1008: 00 01 5c fc\tbne $r6, $r0, 2af6a\n' + '00002000 :\n' + ' 2000: fc 00\t\tpush25 $r6, #0 ! {$r6, $fp, $gp, $lp} \n' + ' 2002: f0 0e fc c5\tjal 1000 \n' + ' 2006: f0 0e bd 3b\tj 53968 \n' + ' 200a: de ad be ef\tswi.gp $r0, [ + #-11036]\n' + '00004000 :\n' + ' 4000: 47 70\t\tmovi55 $r0, #1\n' + '00010000 :' + ) + function_map = self.analyzer.AnalyzeDisassembly(disasm_text) + func_hook_task = sa.Function(0x1000, 'hook_task', 48, [ + sa.Callsite(0x1006, 0x100929de, True, None)]) + expect_funcmap = { + 0x1000: func_hook_task, + 0x2000: sa.Function(0x2000, 'console_task', 16, + [sa.Callsite(0x2002, 0x1000, False, func_hook_task), + sa.Callsite(0x2006, 0x53968, True, None)]), + 0x4000: sa.Function(0x4000, 'touchpad_calc', 0, []), + } + self.assertEqual(function_map, expect_funcmap) + + def testArmAnalyzeDisassembly(self): + disasm_text = ( + '\n' + 'build/{BOARD}/RW/ec.RW.elf: file format elf32-littlearm' '\n' 'Disassembly of section .text:\n' '\n' @@ -597,8 +634,69 @@ class StackAnalyzerTest(unittest.TestCase): @mock.patch('subprocess.check_output') @mock.patch('stack_analyzer.StackAnalyzer.AddressToLine') - def testAnalyze(self, addrtoline_mock, checkoutput_mock): + def testAndesAnalyze(self, addrtoline_mock, checkoutput_mock): disasm_text = ( + '\n' + 'build/{BOARD}/RW/ec.RW.elf: file format elf32-nds32le' + '\n' + 'Disassembly of section .text:\n' + '\n' + '00000900 :\n' + ' ...\n' + '00001000 :\n' + ' 1000: fc 00\t\tpush25 $r10, #16 ! {$r6~$r10, $fp, $gp, $lp}\n' + ' 1002: 47 70\t\tmovi55 $r0, #1\n' + ' 1006: 00 01 5c fc\tbne $r6, $r0, 2af6a\n' + '00002000 :\n' + ' 2000: fc 00\t\tpush25 $r6, #0 ! {$r6, $fp, $gp, $lp} \n' + ' 2002: f0 0e fc c5\tjal 1000 \n' + ' 2006: f0 0e bd 3b\tj 53968 \n' + ' 200a: 12 34 56 78\tjral5 $r0\n' + ) + + addrtoline_mock.return_value = [('??', '??', 0)] + self.analyzer.annotation = { + 'exception_frame_size': 64, + 'remove': [['fake_func']], + } + + with mock.patch('__builtin__.print') as print_mock: + checkoutput_mock.return_value = disasm_text + self.analyzer.Analyze() + print_mock.assert_has_calls([ + mock.call( + 'Task: HOOKS, Max size: 96 (32 + 64), Allocated size: 2048'), + mock.call('Call Trace:'), + mock.call(' hook_task (32) [??:0] 1000'), + mock.call( + 'Task: CONSOLE, Max size: 112 (48 + 64), Allocated size: 460'), + mock.call('Call Trace:'), + mock.call(' console_task (16) [??:0] 2000'), + mock.call(' -> ??[??:0] 2002'), + mock.call(' hook_task (32) [??:0] 1000'), + mock.call('Unresolved indirect callsites:'), + mock.call(' In function console_task:'), + mock.call(' -> ??[??:0] 200a'), + mock.call('Unresolved annotation signatures:'), + mock.call(' fake_func: function is not found'), + ]) + + with self.assertRaisesRegexp(sa.StackAnalyzerError, + 'Failed to run objdump.'): + checkoutput_mock.side_effect = OSError() + self.analyzer.Analyze() + + with self.assertRaisesRegexp(sa.StackAnalyzerError, + 'objdump failed to disassemble.'): + checkoutput_mock.side_effect = subprocess.CalledProcessError(1, '') + self.analyzer.Analyze() + + @mock.patch('subprocess.check_output') + @mock.patch('stack_analyzer.StackAnalyzer.AddressToLine') + def testArmAnalyze(self, addrtoline_mock, checkoutput_mock): + disasm_text = ( + '\n' + 'build/{BOARD}/RW/ec.RW.elf: file format elf32-littlearm' '\n' 'Disassembly of section .text:\n' '\n' -- cgit v1.2.1