def testAnalyzeDisassembly(self): disasm_text = ( '\n' 'Disassembly of section .text:\n' '\n' '00000900 <wook_task>:\n' ' ...\n' '00001000 <hook_task>:\n' ' 1000: dead beef\tfake\n' ' 1004: 4770\t\tbx lr\n' ' 1006: b113\tcbz r3, 100929de <flash_command_write>\n' ' 1008: 00015cfc\t.word 0x00015cfc\n' '00002000 <console_task>:\n' ' 2000: b508\t\tpush {r3, lr} ; malformed comments,; r0, r1 \n' ' 2002: f00e fcc5\tbl 1000 <hook_task>\n' ' 2006: f00e bd3b\tb.w 53968 <get_program_memory_addr>\n' ' 200a: dead beef\tfake\n' '00004000 <touchpad_calc>:\n' ' 4000: 4770\t\tbx lr\n' '00010000 <look_task>:' ) function_map = self.analyzer.AnalyzeDisassembly(disasm_text) func_hook_task = sa.Function(0x1000, 'hook_task', 0, [ sa.Callsite(0x1006, 0x100929de, True, None)]) expect_funcmap = { 0x1000: func_hook_task, 0x2000: sa.Function(0x2000, 'console_task', 8, [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 testAndesAnalyzeDisassembly(self): disasm_text = ( '\n' 'build/{BOARD}/RW/ec.RW.elf: file format elf32-nds32le' '\n' 'Disassembly of section .text:\n' '\n' '00000900 <wook_task>:\n' ' ...\n' '00001000 <hook_task>:\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 <flash_command_write>\n' ' 1008: 00 01 5c fc\tbne $r6, $r0, 2af6a\n' '00002000 <console_task>:\n' ' 2000: fc 00\t\tpush25 $r6, #0 ! {$r6, $fp, $gp, $lp} \n' ' 2002: f0 0e fc c5\tjal 1000 <hook_task>\n' ' 2006: f0 0e bd 3b\tj 53968 <get_program_memory_addr>\n' ' 200a: de ad be ef\tswi.gp $r0, [ + #-11036]\n' '00004000 <touchpad_calc>:\n' ' 4000: 47 70\t\tmovi55 $r0, #1\n' '00010000 <look_task>:' ) 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 testPreprocessAnnotation(self): funcs = { 0x1000: sa.Function(0x1000, 'hook_task', 0, []), 0x2000: sa.Function(0x2000, 'console_task', 0, []), 0x4000: sa.Function(0x4000, 'touchpad_calc', 0, []), } funcs[0x1000].callsites = [ sa.Callsite(0x1002, 0x1000, False, funcs[0x1000]) ] funcs[0x2000].callsites = [ sa.Callsite(0x2002, 0x1000, False, funcs[0x1000]), sa.Callsite(0x2006, None, True, None), ] add_set = { (funcs[0x2000], funcs[0x2000]), (funcs[0x2000], funcs[0x4000]), (funcs[0x4000], funcs[0x1000]), (funcs[0x4000], funcs[0x2000]), } remove_list = [ [funcs[0x1000]], [funcs[0x2000], funcs[0x2000]], [funcs[0x4000], funcs[0x1000]], [funcs[0x2000], funcs[0x4000], funcs[0x2000]], [funcs[0x4000], funcs[0x1000], funcs[0x4000]], ] eliminated_addrs = {0x2006} remaining_remove_list = self.analyzer.PreprocessAnnotation( funcs, add_set, remove_list, eliminated_addrs) expect_funcs = { 0x1000: sa.Function(0x1000, 'hook_task', 0, []), 0x2000: sa.Function(0x2000, 'console_task', 0, []), 0x4000: sa.Function(0x4000, 'touchpad_calc', 0, []), } expect_funcs[0x2000].callsites = [ sa.Callsite(None, 0x4000, False, expect_funcs[0x4000]) ] expect_funcs[0x4000].callsites = [ sa.Callsite(None, 0x2000, False, expect_funcs[0x2000]) ] self.assertEqual(funcs, expect_funcs) self.assertEqual(remaining_remove_list, [ [funcs[0x2000], funcs[0x4000], funcs[0x2000]], ])
def testAnalyzeCallGraph(self): funcs = { 0x1000: sa.Function(0x1000, 'hook_task', 0, []), 0x2000: sa.Function(0x2000, 'console_task', 8, []), 0x3000: sa.Function(0x3000, 'task_a', 12, []), 0x4000: sa.Function(0x4000, 'task_b', 96, []), 0x5000: sa.Function(0x5000, 'task_c', 32, []), 0x6000: sa.Function(0x6000, 'task_d', 100, []), 0x7000: sa.Function(0x7000, 'task_e', 24, []), 0x8000: sa.Function(0x8000, 'task_f', 20, []), 0x9000: sa.Function(0x9000, 'task_g', 20, []), 0x10000: sa.Function(0x10000, 'task_x', 16, []), } funcs[0x1000].callsites = [ sa.Callsite(0x1002, 0x3000, False, funcs[0x3000]), sa.Callsite(0x1006, 0x4000, False, funcs[0x4000]) ] funcs[0x2000].callsites = [ sa.Callsite(0x2002, 0x5000, False, funcs[0x5000]), sa.Callsite(0x2006, 0x2000, False, funcs[0x2000]), sa.Callsite(0x200a, 0x10000, False, funcs[0x10000]) ] funcs[0x3000].callsites = [ sa.Callsite(0x3002, 0x4000, False, funcs[0x4000]), sa.Callsite(0x3006, 0x1000, False, funcs[0x1000]) ] funcs[0x4000].callsites = [ sa.Callsite(0x4002, 0x6000, True, funcs[0x6000]), sa.Callsite(0x4006, 0x7000, False, funcs[0x7000]), sa.Callsite(0x400a, 0x8000, False, funcs[0x8000]) ] funcs[0x5000].callsites = [ sa.Callsite(0x5002, 0x4000, False, funcs[0x4000]) ] funcs[0x7000].callsites = [ sa.Callsite(0x7002, 0x7000, False, funcs[0x7000]) ] funcs[0x8000].callsites = [ sa.Callsite(0x8002, 0x9000, False, funcs[0x9000]) ] funcs[0x9000].callsites = [ sa.Callsite(0x9002, 0x4000, False, funcs[0x4000]) ] funcs[0x10000].callsites = [ sa.Callsite(0x10002, 0x2000, False, funcs[0x2000]) ] cycles = self.analyzer.AnalyzeCallGraph( funcs, [[funcs[0x2000]] * 2, [funcs[0x10000], funcs[0x2000]] * 3, [funcs[0x1000], funcs[0x3000], funcs[0x1000]]]) expect_func_stack = { 0x1000: (268, [ funcs[0x1000], funcs[0x3000], funcs[0x4000], funcs[0x8000], funcs[0x9000], funcs[0x4000], funcs[0x7000] ]), 0x2000: (208, [ funcs[0x2000], funcs[0x10000], funcs[0x2000], funcs[0x10000], funcs[0x2000], funcs[0x5000], funcs[0x4000], funcs[0x7000] ]), 0x3000: (280, [ funcs[0x3000], funcs[0x1000], funcs[0x3000], funcs[0x4000], funcs[0x8000], funcs[0x9000], funcs[0x4000], funcs[0x7000] ]), 0x4000: (120, [funcs[0x4000], funcs[0x7000]]), 0x5000: (152, [funcs[0x5000], funcs[0x4000], funcs[0x7000]]), 0x6000: (100, [funcs[0x6000]]), 0x7000: (24, [funcs[0x7000]]), 0x8000: (160, [funcs[0x8000], funcs[0x9000], funcs[0x4000], funcs[0x7000]]), 0x9000: (140, [funcs[0x9000], funcs[0x4000], funcs[0x7000]]), 0x10000: (200, [ funcs[0x10000], funcs[0x2000], funcs[0x10000], funcs[0x2000], funcs[0x5000], funcs[0x4000], funcs[0x7000] ]), } expect_cycles = [ {funcs[0x4000], funcs[0x8000], funcs[0x9000]}, {funcs[0x7000]}, ] for func in funcs.values(): (stack_max_usage, stack_max_path) = expect_func_stack[func.address] self.assertEqual(func.stack_max_usage, stack_max_usage) self.assertEqual(func.stack_max_path, stack_max_path) self.assertEqual(len(cycles), len(expect_cycles)) for cycle in cycles: self.assertTrue(cycle in expect_cycles)
def testFunction(self): func_a = sa.Function(0x100, 'a', 0, []) func_b = sa.Function(0x200, 'b', 0, []) self.assertEqual(func_a, func_a) self.assertNotEqual(func_a, func_b) self.assertNotEqual(func_a, None)
def testResolveAnnotation(self): self.analyzer.annotation = {} (add_rules, remove_rules, invalid_sigtxts) = self.analyzer.LoadAnnotation() self.assertEqual(add_rules, {}) self.assertEqual(remove_rules, []) self.assertEqual(invalid_sigtxts, set()) self.analyzer.annotation = {'add': None, 'remove': None} (add_rules, remove_rules, invalid_sigtxts) = self.analyzer.LoadAnnotation() self.assertEqual(add_rules, {}) 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( list.sort(remove_rules), list.sort([ [('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, {'['}) self.analyzer.annotation = { 'add': { 'touchpad_calc': [dict(name='__array', stride=8, offset=4)], } } (add_rules, remove_rules, invalid_sigtxts) = self.analyzer.LoadAnnotation() self.assertEqual( add_rules, { ('touchpad_calc', None, None): set([('console_task', None, None), ('hook_task', None, None)]) }) funcs = { 0x1000: sa.Function(0x1000, 'hook_task', 0, []), 0x2000: sa.Function(0x2000, 'console_task', 0, []), 0x4000: sa.Function(0x4000, 'touchpad_calc', 0, []), 0x5000: sa.Function(0x5000, 'touchpad_calc.constprop.42', 0, []), 0x13000: sa.Function(0x13000, 'inlined_mul', 0, []), 0x13100: sa.Function(0x13100, 'inlined_mul', 0, []), } funcs[0x1000].callsites = [sa.Callsite(0x1002, None, False, None)] # Set address_to_line_cache to fake the results of addr2line. self.analyzer.address_to_line_cache = { (0x1000, False): [('hook_task', os.path.abspath('a.c'), 10)], (0x1002, False): [('toot_calc', os.path.abspath('t.c'), 1234)], (0x2000, False): [('console_task', os.path.abspath('b.c'), 20)], (0x4000, False): [('toudhpad_calc', os.path.abspath('a.c'), 20)], (0x5000, False): [('touchpad_calc.constprop.42', os.path.abspath('b.c'), 40)], (0x12000, False): [('trackpad_range', os.path.abspath('t.c'), 10)], (0x13000, False): [('inlined_mul', os.path.abspath('x.c'), 12)], (0x13100, False): [('inlined_mul', os.path.abspath('x.c'), 12)], } self.analyzer.annotation = { 'add': { 'hook_task.lto.573': ['touchpad_calc.lto.2501[a.c]'], 'console_task': ['touchpad_calc[b.c]', 'inlined_mul_alias'], 'hook_task[q.c]': ['hook_task'], 'inlined_mul[x.c]': ['inlined_mul'], 'toot_calc[t.c:1234]': ['hook_task'], }, 'remove': [ ['touchpad?calc['], 'touchpad_calc', ['touchpad_calc[a.c]'], ['task_unk[a.c]'], ['touchpad_calc[x/a.c]'], ['trackpad_range'], ['inlined_mul'], ['inlined_mul', 'console_task', 'touchpad_calc[a.c]'], ['inlined_mul', 'inlined_mul_alias', 'console_task'], ['inlined_mul', 'inlined_mul_alias', 'console_task'], ], } (add_rules, remove_rules, invalid_sigtxts) = self.analyzer.LoadAnnotation() self.assertEqual(invalid_sigtxts, {'touchpad?calc['}) signature_set = set() for src_sig, dst_sigs in add_rules.items(): signature_set.add(src_sig) signature_set.update(dst_sigs) for remove_sigs in remove_rules: signature_set.update(remove_sigs) (signature_map, failed_sigs) = self.analyzer.MapAnnotation(funcs, signature_set) result = self.analyzer.ResolveAnnotation(funcs) (add_set, remove_list, eliminated_addrs, failed_sigs) = result expect_signature_map = { ('hook_task', None, None): {funcs[0x1000]}, ('touchpad_calc', os.path.abspath('a.c'), None): {funcs[0x4000]}, ('touchpad_calc', os.path.abspath('b.c'), None): {funcs[0x5000]}, ('console_task', None, None): {funcs[0x2000]}, ('inlined_mul_alias', None, None): {funcs[0x13100]}, ('inlined_mul', os.path.abspath('x.c'), None): {funcs[0x13000], funcs[0x13100]}, ('inlined_mul', None, None): {funcs[0x13000], funcs[0x13100]}, } self.assertEqual(len(signature_map), len(expect_signature_map)) for sig, funclist in signature_map.items(): self.assertEqual(set(funclist), expect_signature_map[sig]) self.assertEqual( add_set, { (funcs[0x1000], funcs[0x4000]), (funcs[0x1000], funcs[0x1000]), (funcs[0x2000], funcs[0x5000]), (funcs[0x2000], funcs[0x13100]), (funcs[0x13000], funcs[0x13000]), (funcs[0x13000], funcs[0x13100]), (funcs[0x13100], funcs[0x13000]), (funcs[0x13100], funcs[0x13100]), }) expect_remove_list = [ [funcs[0x4000]], [funcs[0x13000]], [funcs[0x13100]], [funcs[0x13000], funcs[0x2000], funcs[0x4000]], [funcs[0x13100], funcs[0x2000], funcs[0x4000]], [funcs[0x13000], funcs[0x13100], funcs[0x2000]], [funcs[0x13100], funcs[0x13100], funcs[0x2000]], ] self.assertEqual(len(remove_list), len(expect_remove_list)) for remove_path in remove_list: self.assertTrue(remove_path in expect_remove_list) self.assertEqual(eliminated_addrs, {0x1002}) self.assertEqual( failed_sigs, { ('touchpad?calc[', sa.StackAnalyzer.ANNOTATION_ERROR_INVALID), ('touchpad_calc', sa.StackAnalyzer.ANNOTATION_ERROR_AMBIGUOUS), ('hook_task[q.c]', sa.StackAnalyzer.ANNOTATION_ERROR_NOTFOUND), ('task_unk[a.c]', sa.StackAnalyzer.ANNOTATION_ERROR_NOTFOUND), ('touchpad_calc[x/a.c]', sa.StackAnalyzer.ANNOTATION_ERROR_NOTFOUND), ('trackpad_range', sa.StackAnalyzer.ANNOTATION_ERROR_NOTFOUND), })