xref: /aosp_15_r20/system/extras/simpleperf/scripts/test/tools_test.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*288bf522SAndroid Build Coastguard Worker#
3*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project
4*288bf522SAndroid Build Coastguard Worker#
5*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*288bf522SAndroid Build Coastguard Worker#
9*288bf522SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*288bf522SAndroid Build Coastguard Worker#
11*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*288bf522SAndroid Build Coastguard Worker# limitations under the License.
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Workerimport io
18*288bf522SAndroid Build Coastguard Workerimport os
19*288bf522SAndroid Build Coastguard Workerfrom pathlib import Path
20*288bf522SAndroid Build Coastguard Worker
21*288bf522SAndroid Build Coastguard Workerfrom binary_cache_builder import BinaryCacheBuilder
22*288bf522SAndroid Build Coastguard Workerfrom simpleperf_utils import (Addr2Nearestline, AddrRange, BinaryFinder, Disassembly, Objdump,
23*288bf522SAndroid Build Coastguard Worker                              ReadElf, SourceFileSearcher, is_windows, remove)
24*288bf522SAndroid Build Coastguard Workerfrom . test_utils import TestBase, TestHelper
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker
27*288bf522SAndroid Build Coastguard Workerclass TestTools(TestBase):
28*288bf522SAndroid Build Coastguard Worker    def test_addr2nearestline(self):
29*288bf522SAndroid Build Coastguard Worker        self.run_addr2nearestline_test(True)
30*288bf522SAndroid Build Coastguard Worker        self.run_addr2nearestline_test(False)
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker    def run_addr2nearestline_test(self, with_function_name):
33*288bf522SAndroid Build Coastguard Worker        test_map = {
34*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_arm64': [
35*288bf522SAndroid Build Coastguard Worker                {
36*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x112c,
37*288bf522SAndroid Build Coastguard Worker                    'addr': 0x112c,
38*288bf522SAndroid Build Coastguard Worker                    'source': 'system/extras/simpleperf/runtest/two_functions.cpp:20',
39*288bf522SAndroid Build Coastguard Worker                    'function': 'main',
40*288bf522SAndroid Build Coastguard Worker                },
41*288bf522SAndroid Build Coastguard Worker                {
42*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x104c,
43*288bf522SAndroid Build Coastguard Worker                    'addr': 0x105c,
44*288bf522SAndroid Build Coastguard Worker                    'source': "system/extras/simpleperf/runtest/two_functions.cpp:7",
45*288bf522SAndroid Build Coastguard Worker                    'function': "Function1()",
46*288bf522SAndroid Build Coastguard Worker                },
47*288bf522SAndroid Build Coastguard Worker            ],
48*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_arm': [
49*288bf522SAndroid Build Coastguard Worker                {
50*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x1304,
51*288bf522SAndroid Build Coastguard Worker                    'addr': 0x131a,
52*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:8
53*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
54*288bf522SAndroid Build Coastguard Worker                    'function': """Function1()
55*288bf522SAndroid Build Coastguard Worker                                   main""",
56*288bf522SAndroid Build Coastguard Worker                },
57*288bf522SAndroid Build Coastguard Worker                {
58*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x1304,
59*288bf522SAndroid Build Coastguard Worker                    'addr': 0x131c,
60*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:16
61*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
62*288bf522SAndroid Build Coastguard Worker                    'function': """Function2()
63*288bf522SAndroid Build Coastguard Worker                                   main""",
64*288bf522SAndroid Build Coastguard Worker                }
65*288bf522SAndroid Build Coastguard Worker            ],
66*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_x86_64': [
67*288bf522SAndroid Build Coastguard Worker                {
68*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x19e0,
69*288bf522SAndroid Build Coastguard Worker                    'addr': 0x19f6,
70*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:8
71*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
72*288bf522SAndroid Build Coastguard Worker                    'function': """Function1()
73*288bf522SAndroid Build Coastguard Worker                                   main""",
74*288bf522SAndroid Build Coastguard Worker                },
75*288bf522SAndroid Build Coastguard Worker                {
76*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x19e0,
77*288bf522SAndroid Build Coastguard Worker                    'addr': 0x1a19,
78*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:16
79*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
80*288bf522SAndroid Build Coastguard Worker                    'function': """Function2()
81*288bf522SAndroid Build Coastguard Worker                                   main""",
82*288bf522SAndroid Build Coastguard Worker                }
83*288bf522SAndroid Build Coastguard Worker            ],
84*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_x86': [
85*288bf522SAndroid Build Coastguard Worker                {
86*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x16e0,
87*288bf522SAndroid Build Coastguard Worker                    'addr': 0x16f6,
88*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:8
89*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:22""",
90*288bf522SAndroid Build Coastguard Worker                    'function': """Function1()
91*288bf522SAndroid Build Coastguard Worker                                   main""",
92*288bf522SAndroid Build Coastguard Worker                },
93*288bf522SAndroid Build Coastguard Worker                {
94*288bf522SAndroid Build Coastguard Worker                    'func_addr': 0x16e0,
95*288bf522SAndroid Build Coastguard Worker                    'addr': 0x1710,
96*288bf522SAndroid Build Coastguard Worker                    'source': """system/extras/simpleperf/runtest/two_functions.cpp:16
97*288bf522SAndroid Build Coastguard Worker                                 system/extras/simpleperf/runtest/two_functions.cpp:23""",
98*288bf522SAndroid Build Coastguard Worker                    'function': """Function2()
99*288bf522SAndroid Build Coastguard Worker                                   main""",
100*288bf522SAndroid Build Coastguard Worker                }
101*288bf522SAndroid Build Coastguard Worker            ],
102*288bf522SAndroid Build Coastguard Worker        }
103*288bf522SAndroid Build Coastguard Worker
104*288bf522SAndroid Build Coastguard Worker        binary_finder = BinaryFinder(TestHelper.testdata_dir, ReadElf(TestHelper.ndk_path))
105*288bf522SAndroid Build Coastguard Worker        addr2line = Addr2Nearestline(TestHelper.ndk_path, binary_finder, with_function_name)
106*288bf522SAndroid Build Coastguard Worker        for dso_path in test_map:
107*288bf522SAndroid Build Coastguard Worker            test_addrs = test_map[dso_path]
108*288bf522SAndroid Build Coastguard Worker            for test_addr in test_addrs:
109*288bf522SAndroid Build Coastguard Worker                addr2line.add_addr(dso_path, None, test_addr['func_addr'], test_addr['addr'])
110*288bf522SAndroid Build Coastguard Worker        addr2line.convert_addrs_to_lines(4)
111*288bf522SAndroid Build Coastguard Worker        for dso_path in test_map:
112*288bf522SAndroid Build Coastguard Worker            dso = addr2line.get_dso(dso_path)
113*288bf522SAndroid Build Coastguard Worker            self.assertIsNotNone(dso, dso_path)
114*288bf522SAndroid Build Coastguard Worker            test_addrs = test_map[dso_path]
115*288bf522SAndroid Build Coastguard Worker            for test_addr in test_addrs:
116*288bf522SAndroid Build Coastguard Worker                expected_files = []
117*288bf522SAndroid Build Coastguard Worker                expected_lines = []
118*288bf522SAndroid Build Coastguard Worker                expected_functions = []
119*288bf522SAndroid Build Coastguard Worker                for line in test_addr['source'].split('\n'):
120*288bf522SAndroid Build Coastguard Worker                    items = line.split(':')
121*288bf522SAndroid Build Coastguard Worker                    expected_files.append(items[0].strip())
122*288bf522SAndroid Build Coastguard Worker                    expected_lines.append(int(items[1]))
123*288bf522SAndroid Build Coastguard Worker                for line in test_addr['function'].split('\n'):
124*288bf522SAndroid Build Coastguard Worker                    expected_functions.append(line.strip())
125*288bf522SAndroid Build Coastguard Worker                self.assertEqual(len(expected_files), len(expected_functions))
126*288bf522SAndroid Build Coastguard Worker
127*288bf522SAndroid Build Coastguard Worker                if with_function_name:
128*288bf522SAndroid Build Coastguard Worker                    expected_source = list(zip(expected_files, expected_lines, expected_functions))
129*288bf522SAndroid Build Coastguard Worker                else:
130*288bf522SAndroid Build Coastguard Worker                    expected_source = list(zip(expected_files, expected_lines))
131*288bf522SAndroid Build Coastguard Worker
132*288bf522SAndroid Build Coastguard Worker                actual_source = addr2line.get_addr_source(dso, test_addr['addr'])
133*288bf522SAndroid Build Coastguard Worker                if is_windows():
134*288bf522SAndroid Build Coastguard Worker                    self.assertIsNotNone(actual_source, 'for %s:0x%x' %
135*288bf522SAndroid Build Coastguard Worker                                         (dso_path, test_addr['addr']))
136*288bf522SAndroid Build Coastguard Worker                    for i, source in enumerate(actual_source):
137*288bf522SAndroid Build Coastguard Worker                        new_source = list(source)
138*288bf522SAndroid Build Coastguard Worker                        new_source[0] = new_source[0].replace('\\', '/')
139*288bf522SAndroid Build Coastguard Worker                        actual_source[i] = tuple(new_source)
140*288bf522SAndroid Build Coastguard Worker
141*288bf522SAndroid Build Coastguard Worker                self.assertEqual(actual_source, expected_source,
142*288bf522SAndroid Build Coastguard Worker                                 'for %s:0x%x, expected source %s, actual source %s' %
143*288bf522SAndroid Build Coastguard Worker                                 (dso_path, test_addr['addr'], expected_source, actual_source))
144*288bf522SAndroid Build Coastguard Worker
145*288bf522SAndroid Build Coastguard Worker    def test_addr2nearestline_parse_output(self):
146*288bf522SAndroid Build Coastguard Worker        output = """
147*288bf522SAndroid Build Coastguard Worker0x104c
148*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:6:0
149*288bf522SAndroid Build Coastguard Worker
150*288bf522SAndroid Build Coastguard Worker0x1094
151*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:9:10
152*288bf522SAndroid Build Coastguard Worker
153*288bf522SAndroid Build Coastguard Worker0x10bb
154*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:11:1
155*288bf522SAndroid Build Coastguard Worker
156*288bf522SAndroid Build Coastguard Worker0x10bc
157*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:13:0
158*288bf522SAndroid Build Coastguard Worker
159*288bf522SAndroid Build Coastguard Worker0x1104
160*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:16:10
161*288bf522SAndroid Build Coastguard Worker
162*288bf522SAndroid Build Coastguard Worker0x112b
163*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:18:1
164*288bf522SAndroid Build Coastguard Worker
165*288bf522SAndroid Build Coastguard Worker0x112c
166*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:20:0
167*288bf522SAndroid Build Coastguard Worker
168*288bf522SAndroid Build Coastguard Worker0x113c
169*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:22:5
170*288bf522SAndroid Build Coastguard Worker
171*288bf522SAndroid Build Coastguard Worker0x1140
172*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:23:5
173*288bf522SAndroid Build Coastguard Worker
174*288bf522SAndroid Build Coastguard Worker0x1147
175*288bf522SAndroid Build Coastguard Workersystem/extras/simpleperf/runtest/two_functions.cpp:21:3
176*288bf522SAndroid Build Coastguard Worker        """
177*288bf522SAndroid Build Coastguard Worker        dso = Addr2Nearestline.Dso(None)
178*288bf522SAndroid Build Coastguard Worker        binary_finder = BinaryFinder(TestHelper.testdata_dir, ReadElf(TestHelper.ndk_path))
179*288bf522SAndroid Build Coastguard Worker        addr2line = Addr2Nearestline(TestHelper.ndk_path, binary_finder, False)
180*288bf522SAndroid Build Coastguard Worker        addr_map = addr2line.parse_line_output(output, dso)
181*288bf522SAndroid Build Coastguard Worker        expected_addr_map = {
182*288bf522SAndroid Build Coastguard Worker            0x104c: [('system/extras/simpleperf/runtest/two_functions.cpp', 6)],
183*288bf522SAndroid Build Coastguard Worker            0x1094: [('system/extras/simpleperf/runtest/two_functions.cpp', 9)],
184*288bf522SAndroid Build Coastguard Worker            0x10bb: [('system/extras/simpleperf/runtest/two_functions.cpp', 11)],
185*288bf522SAndroid Build Coastguard Worker            0x10bc: [('system/extras/simpleperf/runtest/two_functions.cpp', 13)],
186*288bf522SAndroid Build Coastguard Worker            0x1104: [('system/extras/simpleperf/runtest/two_functions.cpp', 16)],
187*288bf522SAndroid Build Coastguard Worker            0x112b: [('system/extras/simpleperf/runtest/two_functions.cpp', 18)],
188*288bf522SAndroid Build Coastguard Worker            0x112c: [('system/extras/simpleperf/runtest/two_functions.cpp', 20)],
189*288bf522SAndroid Build Coastguard Worker            0x113c: [('system/extras/simpleperf/runtest/two_functions.cpp', 22)],
190*288bf522SAndroid Build Coastguard Worker            0x1140: [('system/extras/simpleperf/runtest/two_functions.cpp', 23)],
191*288bf522SAndroid Build Coastguard Worker            0x1147: [('system/extras/simpleperf/runtest/two_functions.cpp', 21)],
192*288bf522SAndroid Build Coastguard Worker        }
193*288bf522SAndroid Build Coastguard Worker        self.assertEqual(len(expected_addr_map), len(addr_map))
194*288bf522SAndroid Build Coastguard Worker        for addr in expected_addr_map:
195*288bf522SAndroid Build Coastguard Worker            expected_source_list = expected_addr_map[addr]
196*288bf522SAndroid Build Coastguard Worker            source_list = addr_map[addr]
197*288bf522SAndroid Build Coastguard Worker            self.assertEqual(len(expected_source_list), len(source_list))
198*288bf522SAndroid Build Coastguard Worker            for expected_source, source in zip(expected_source_list, source_list):
199*288bf522SAndroid Build Coastguard Worker                file_path = dso.file_id_to_name[source[0]]
200*288bf522SAndroid Build Coastguard Worker                self.assertEqual(file_path, expected_source[0])
201*288bf522SAndroid Build Coastguard Worker                self.assertEqual(source[1], expected_source[1])
202*288bf522SAndroid Build Coastguard Worker
203*288bf522SAndroid Build Coastguard Worker    def test_objdump(self):
204*288bf522SAndroid Build Coastguard Worker        test_map = {
205*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_arm64': {
206*288bf522SAndroid Build Coastguard Worker                'start_addr': 0x112c,
207*288bf522SAndroid Build Coastguard Worker                'len': 28,
208*288bf522SAndroid Build Coastguard Worker                'expected_items': [
209*288bf522SAndroid Build Coastguard Worker                    ('main', 0),
210*288bf522SAndroid Build Coastguard Worker                    ('two_functions.cpp:20', 0),
211*288bf522SAndroid Build Coastguard Worker                    ('1134:      	add	x29, sp, #0x10', 0x1134),
212*288bf522SAndroid Build Coastguard Worker                ],
213*288bf522SAndroid Build Coastguard Worker            },
214*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_arm': {
215*288bf522SAndroid Build Coastguard Worker                'start_addr': 0x1304,
216*288bf522SAndroid Build Coastguard Worker                'len': 40,
217*288bf522SAndroid Build Coastguard Worker                'expected_items': [
218*288bf522SAndroid Build Coastguard Worker                    ('main', 0),
219*288bf522SAndroid Build Coastguard Worker                    ('two_functions.cpp:20', 0),
220*288bf522SAndroid Build Coastguard Worker                    ('1318:      	bne	0x1312 <main+0xe>', 0x1318),
221*288bf522SAndroid Build Coastguard Worker                ],
222*288bf522SAndroid Build Coastguard Worker            },
223*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_x86_64': {
224*288bf522SAndroid Build Coastguard Worker                'start_addr': 0x19e0,
225*288bf522SAndroid Build Coastguard Worker                'len': 151,
226*288bf522SAndroid Build Coastguard Worker                'expected_items': [
227*288bf522SAndroid Build Coastguard Worker                    ('main', 0),
228*288bf522SAndroid Build Coastguard Worker                    ('two_functions.cpp:20', 0),
229*288bf522SAndroid Build Coastguard Worker                    (r'19f0:      	movl	%eax, 0x2462(%rip)', 0x19f0),
230*288bf522SAndroid Build Coastguard Worker                ],
231*288bf522SAndroid Build Coastguard Worker            },
232*288bf522SAndroid Build Coastguard Worker            '/simpleperf_runtest_two_functions_x86': {
233*288bf522SAndroid Build Coastguard Worker                'start_addr': 0x16e0,
234*288bf522SAndroid Build Coastguard Worker                'len': 65,
235*288bf522SAndroid Build Coastguard Worker                'expected_items': [
236*288bf522SAndroid Build Coastguard Worker                    ('main', 0),
237*288bf522SAndroid Build Coastguard Worker                    ('two_functions.cpp:20', 0),
238*288bf522SAndroid Build Coastguard Worker                    (r'16f7:      	cmpl	$0x5f5e100, %ecx', 0x16f7),
239*288bf522SAndroid Build Coastguard Worker                ],
240*288bf522SAndroid Build Coastguard Worker            },
241*288bf522SAndroid Build Coastguard Worker        }
242*288bf522SAndroid Build Coastguard Worker        binary_finder = BinaryFinder(TestHelper.testdata_dir, ReadElf(TestHelper.ndk_path))
243*288bf522SAndroid Build Coastguard Worker        objdump = Objdump(TestHelper.ndk_path, binary_finder)
244*288bf522SAndroid Build Coastguard Worker        for dso_path in test_map:
245*288bf522SAndroid Build Coastguard Worker            dso = test_map[dso_path]
246*288bf522SAndroid Build Coastguard Worker            dso_info = objdump.get_dso_info(dso_path, None)
247*288bf522SAndroid Build Coastguard Worker            self.assertIsNotNone(dso_info, dso_path)
248*288bf522SAndroid Build Coastguard Worker            addr_range = AddrRange(dso['start_addr'], dso['len'])
249*288bf522SAndroid Build Coastguard Worker            disassembly = objdump.disassemble_function(dso_info, addr_range)
250*288bf522SAndroid Build Coastguard Worker            self.assertTrue(disassembly, dso_path)
251*288bf522SAndroid Build Coastguard Worker            self._check_disassembly(disassembly, dso_path, dso)
252*288bf522SAndroid Build Coastguard Worker
253*288bf522SAndroid Build Coastguard Worker            result = objdump.disassemble_functions(dso_info, [addr_range])
254*288bf522SAndroid Build Coastguard Worker            self.assertTrue(result, dso_path)
255*288bf522SAndroid Build Coastguard Worker            self.assertEqual(len(result), 1)
256*288bf522SAndroid Build Coastguard Worker            self._check_disassembly(result[0], dso_path, dso)
257*288bf522SAndroid Build Coastguard Worker
258*288bf522SAndroid Build Coastguard Worker    def _check_disassembly(self, disassembly: Disassembly, dso_path: str, dso) -> None:
259*288bf522SAndroid Build Coastguard Worker        disassemble_code = disassembly.lines
260*288bf522SAndroid Build Coastguard Worker        i = 0
261*288bf522SAndroid Build Coastguard Worker        for expected_line, expected_addr in dso['expected_items']:
262*288bf522SAndroid Build Coastguard Worker            found = False
263*288bf522SAndroid Build Coastguard Worker            while i < len(disassemble_code):
264*288bf522SAndroid Build Coastguard Worker                line, addr = disassemble_code[i]
265*288bf522SAndroid Build Coastguard Worker                if addr == expected_addr and expected_line in line:
266*288bf522SAndroid Build Coastguard Worker                    found = True
267*288bf522SAndroid Build Coastguard Worker                    i += 1
268*288bf522SAndroid Build Coastguard Worker                    break
269*288bf522SAndroid Build Coastguard Worker                i += 1
270*288bf522SAndroid Build Coastguard Worker            if not found:
271*288bf522SAndroid Build Coastguard Worker                s = '\n'.join('%s:0x%x' % item for item in disassemble_code)
272*288bf522SAndroid Build Coastguard Worker                self.fail('for %s, %s:0x%x not found in disassemble code:\n%s' %
273*288bf522SAndroid Build Coastguard Worker                          (dso_path, expected_line, expected_addr, s))
274*288bf522SAndroid Build Coastguard Worker
275*288bf522SAndroid Build Coastguard Worker    def test_objdump_parse_disassembly_for_functions(self):
276*288bf522SAndroid Build Coastguard Worker        # Parse kernel disassembly.
277*288bf522SAndroid Build Coastguard Worker        s = """
278*288bf522SAndroid Build Coastguard Workerffffffc008000000 <_text>:
279*288bf522SAndroid Build Coastguard Worker; _text():
280*288bf522SAndroid Build Coastguard Worker; arch/arm64/kernel/head.S:60
281*288bf522SAndroid Build Coastguard Workerffffffc008000000:      	ccmp	x18, #0x0, #0xd, pl
282*288bf522SAndroid Build Coastguard Workerffffffc008000004:      	b	0xffffffc009b2a37c <primary_entry>
283*288bf522SAndroid Build Coastguard Worker
284*288bf522SAndroid Build Coastguard Workerffffffc008000008 <$d.1>:
285*288bf522SAndroid Build Coastguard Workerffffffc008000008: 00 00 00 00  	.word	0x00000000
286*288bf522SAndroid Build Coastguard Workerffffffc0089bbb30 <readl>:
287*288bf522SAndroid Build Coastguard Worker; readl():
288*288bf522SAndroid Build Coastguard Worker; include/asm-generic/io.h:218
289*288bf522SAndroid Build Coastguard Workerffffffc0089bbb30:      	paciasp
290*288bf522SAndroid Build Coastguard Workerffffffc0089bbb34:      	stp	x29, x30, [sp, #-0x30]!
291*288bf522SAndroid Build Coastguard Worker        """
292*288bf522SAndroid Build Coastguard Worker        addr_ranges = [AddrRange(0xffffffc008000000, 8),
293*288bf522SAndroid Build Coastguard Worker                       AddrRange(0xffffffc008000010, 10),
294*288bf522SAndroid Build Coastguard Worker                       AddrRange(0xffffffc0089bbb30, 20)]
295*288bf522SAndroid Build Coastguard Worker        binary_finder = BinaryFinder(TestHelper.testdata_dir, ReadElf(TestHelper.ndk_path))
296*288bf522SAndroid Build Coastguard Worker        objdump = Objdump(TestHelper.ndk_path, binary_finder)
297*288bf522SAndroid Build Coastguard Worker        result = objdump._parse_disassembly_for_functions(io.StringIO(s), addr_ranges)
298*288bf522SAndroid Build Coastguard Worker        self.assertEqual(len(result), 3)
299*288bf522SAndroid Build Coastguard Worker        self.assertEqual(
300*288bf522SAndroid Build Coastguard Worker            result[0].lines,
301*288bf522SAndroid Build Coastguard Worker            [('ffffffc008000000 <_text>:', 0xffffffc008000000),
302*288bf522SAndroid Build Coastguard Worker             ('; _text():', 0),
303*288bf522SAndroid Build Coastguard Worker             ('; arch/arm64/kernel/head.S:60', 0),
304*288bf522SAndroid Build Coastguard Worker             ('ffffffc008000000:      	ccmp	x18, #0x0, #0xd, pl', 0xffffffc008000000),
305*288bf522SAndroid Build Coastguard Worker             ('ffffffc008000004:      	b	0xffffffc009b2a37c <primary_entry>',
306*288bf522SAndroid Build Coastguard Worker                0xffffffc008000004),
307*288bf522SAndroid Build Coastguard Worker             ('', 0)])
308*288bf522SAndroid Build Coastguard Worker        self.assertEqual(len(result[1].lines), 0)
309*288bf522SAndroid Build Coastguard Worker        self.assertEqual(result[2].lines, [
310*288bf522SAndroid Build Coastguard Worker            ('ffffffc0089bbb30 <readl>:', 0xffffffc0089bbb30),
311*288bf522SAndroid Build Coastguard Worker            ('; readl():', 0),
312*288bf522SAndroid Build Coastguard Worker            ('; include/asm-generic/io.h:218', 0),
313*288bf522SAndroid Build Coastguard Worker            ('ffffffc0089bbb30:      	paciasp', 0xffffffc0089bbb30),
314*288bf522SAndroid Build Coastguard Worker            ('ffffffc0089bbb34:      	stp	x29, x30, [sp, #-0x30]!', 0xffffffc0089bbb34),
315*288bf522SAndroid Build Coastguard Worker            ('', 0)])
316*288bf522SAndroid Build Coastguard Worker
317*288bf522SAndroid Build Coastguard Worker        # Parse user space library disassembly.
318*288bf522SAndroid Build Coastguard Worker        s = """
319*288bf522SAndroid Build Coastguard Worker0000000000200000 <art::gc::collector::ConcurrentCopying::ProcessMarkStack()>:
320*288bf522SAndroid Build Coastguard Worker; art::gc::collector::ConcurrentCopying::ProcessMarkStack():
321*288bf522SAndroid Build Coastguard Worker; art/runtime/gc/collector/concurrent_copying.cc:2121
322*288bf522SAndroid Build Coastguard Worker  200000:      	stp	x29, x30, [sp, #-0x20]!
323*288bf522SAndroid Build Coastguard Worker  200004:      	stp	x20, x19, [sp, #0x10]
324*288bf522SAndroid Build Coastguard Worker        """
325*288bf522SAndroid Build Coastguard Worker        addr_ranges = [AddrRange(0x200000, 8)]
326*288bf522SAndroid Build Coastguard Worker        result = objdump._parse_disassembly_for_functions(io.StringIO(s), addr_ranges)
327*288bf522SAndroid Build Coastguard Worker        self.assertEqual(len(result), 1)
328*288bf522SAndroid Build Coastguard Worker        self.assertEqual(result[0].lines, [
329*288bf522SAndroid Build Coastguard Worker            ('0000000000200000 <art::gc::collector::ConcurrentCopying::ProcessMarkStack()>:',
330*288bf522SAndroid Build Coastguard Worker                0x200000),
331*288bf522SAndroid Build Coastguard Worker            ('; art::gc::collector::ConcurrentCopying::ProcessMarkStack():', 0),
332*288bf522SAndroid Build Coastguard Worker            ('; art/runtime/gc/collector/concurrent_copying.cc:2121', 0),
333*288bf522SAndroid Build Coastguard Worker            ('  200000:      	stp	x29, x30, [sp, #-0x20]!', 0x200000),
334*288bf522SAndroid Build Coastguard Worker            ('  200004:      	stp	x20, x19, [sp, #0x10]', 0x200004),
335*288bf522SAndroid Build Coastguard Worker            ('', 0)])
336*288bf522SAndroid Build Coastguard Worker
337*288bf522SAndroid Build Coastguard Worker    def test_readelf(self):
338*288bf522SAndroid Build Coastguard Worker        test_map = {
339*288bf522SAndroid Build Coastguard Worker            'simpleperf_runtest_two_functions_arm64': {
340*288bf522SAndroid Build Coastguard Worker                'arch': 'arm64',
341*288bf522SAndroid Build Coastguard Worker                'build_id': '0xb4f1b49b0fe9e34e78fb14e5374c930c00000000',
342*288bf522SAndroid Build Coastguard Worker                'sections': ['.note.gnu.build-id', '.dynsym', '.text', '.rodata', '.eh_frame',
343*288bf522SAndroid Build Coastguard Worker                             '.eh_frame_hdr', '.debug_info',  '.debug_line', '.symtab'],
344*288bf522SAndroid Build Coastguard Worker            },
345*288bf522SAndroid Build Coastguard Worker            'simpleperf_runtest_two_functions_arm': {
346*288bf522SAndroid Build Coastguard Worker                'arch': 'arm',
347*288bf522SAndroid Build Coastguard Worker                'build_id': '0x6b5c2ee980465d306b580c5a8bc9767f00000000',
348*288bf522SAndroid Build Coastguard Worker            },
349*288bf522SAndroid Build Coastguard Worker            'simpleperf_runtest_two_functions_x86_64': {
350*288bf522SAndroid Build Coastguard Worker                'arch': 'x86_64',
351*288bf522SAndroid Build Coastguard Worker            },
352*288bf522SAndroid Build Coastguard Worker            'simpleperf_runtest_two_functions_x86': {
353*288bf522SAndroid Build Coastguard Worker                'arch': 'x86',
354*288bf522SAndroid Build Coastguard Worker            }
355*288bf522SAndroid Build Coastguard Worker        }
356*288bf522SAndroid Build Coastguard Worker        readelf = ReadElf(TestHelper.ndk_path)
357*288bf522SAndroid Build Coastguard Worker        for dso_path in test_map:
358*288bf522SAndroid Build Coastguard Worker            dso_info = test_map[dso_path]
359*288bf522SAndroid Build Coastguard Worker            path = os.path.join(TestHelper.testdata_dir, dso_path)
360*288bf522SAndroid Build Coastguard Worker            self.assertEqual(dso_info['arch'], readelf.get_arch(path))
361*288bf522SAndroid Build Coastguard Worker            if 'build_id' in dso_info:
362*288bf522SAndroid Build Coastguard Worker                self.assertEqual(dso_info['build_id'], readelf.get_build_id(path), dso_path)
363*288bf522SAndroid Build Coastguard Worker            if 'sections' in dso_info:
364*288bf522SAndroid Build Coastguard Worker                sections = readelf.get_sections(path)
365*288bf522SAndroid Build Coastguard Worker                for section in dso_info['sections']:
366*288bf522SAndroid Build Coastguard Worker                    self.assertIn(section, sections)
367*288bf522SAndroid Build Coastguard Worker        self.assertEqual(readelf.get_arch('not_exist_file'), 'unknown')
368*288bf522SAndroid Build Coastguard Worker        self.assertEqual(readelf.get_build_id('not_exist_file'), '')
369*288bf522SAndroid Build Coastguard Worker        self.assertEqual(readelf.get_sections('not_exist_file'), [])
370*288bf522SAndroid Build Coastguard Worker
371*288bf522SAndroid Build Coastguard Worker    def test_source_file_searcher(self):
372*288bf522SAndroid Build Coastguard Worker        searcher = SourceFileSearcher(
373*288bf522SAndroid Build Coastguard Worker            [TestHelper.testdata_path('SimpleperfExampleCpp'),
374*288bf522SAndroid Build Coastguard Worker             TestHelper.testdata_path('SimpleperfExampleKotlin')])
375*288bf522SAndroid Build Coastguard Worker
376*288bf522SAndroid Build Coastguard Worker        def format_path(path):
377*288bf522SAndroid Build Coastguard Worker            return os.path.join(TestHelper.testdata_dir, path.replace('/', os.sep))
378*288bf522SAndroid Build Coastguard Worker        # Find a C++ file with pure file name.
379*288bf522SAndroid Build Coastguard Worker        self.assertEqual(
380*288bf522SAndroid Build Coastguard Worker            format_path('SimpleperfExampleCpp/app/src/main/cpp/native-lib.cpp'),
381*288bf522SAndroid Build Coastguard Worker            searcher.get_real_path('native-lib.cpp'))
382*288bf522SAndroid Build Coastguard Worker        # Find a C++ file with an absolute file path.
383*288bf522SAndroid Build Coastguard Worker        self.assertEqual(
384*288bf522SAndroid Build Coastguard Worker            format_path('SimpleperfExampleCpp/app/src/main/cpp/native-lib.cpp'),
385*288bf522SAndroid Build Coastguard Worker            searcher.get_real_path('/data/native-lib.cpp'))
386*288bf522SAndroid Build Coastguard Worker        # Find a Java file.
387*288bf522SAndroid Build Coastguard Worker        self.assertEqual(
388*288bf522SAndroid Build Coastguard Worker            format_path(
389*288bf522SAndroid Build Coastguard Worker                'SimpleperfExampleCpp/app/src/main/java/simpleperf/example/cpp/MainActivity.java'),
390*288bf522SAndroid Build Coastguard Worker            searcher.get_real_path('cpp/MainActivity.java'))
391*288bf522SAndroid Build Coastguard Worker        # Find a Kotlin file.
392*288bf522SAndroid Build Coastguard Worker        self.assertEqual(
393*288bf522SAndroid Build Coastguard Worker            format_path(
394*288bf522SAndroid Build Coastguard Worker                'SimpleperfExampleKotlin/app/src/main/java/simpleperf/example/kotlin/' +
395*288bf522SAndroid Build Coastguard Worker                'MainActivity.kt'),
396*288bf522SAndroid Build Coastguard Worker            searcher.get_real_path('MainActivity.kt'))
397*288bf522SAndroid Build Coastguard Worker
398*288bf522SAndroid Build Coastguard Worker    def test_is_elf_file(self):
399*288bf522SAndroid Build Coastguard Worker        self.assertTrue(ReadElf.is_elf_file(TestHelper.testdata_path(
400*288bf522SAndroid Build Coastguard Worker            'simpleperf_runtest_two_functions_arm')))
401*288bf522SAndroid Build Coastguard Worker        with open('not_elf', 'wb') as fh:
402*288bf522SAndroid Build Coastguard Worker            fh.write(b'\x90123')
403*288bf522SAndroid Build Coastguard Worker        try:
404*288bf522SAndroid Build Coastguard Worker            self.assertFalse(ReadElf.is_elf_file('not_elf'))
405*288bf522SAndroid Build Coastguard Worker        finally:
406*288bf522SAndroid Build Coastguard Worker            remove('not_elf')
407*288bf522SAndroid Build Coastguard Worker
408*288bf522SAndroid Build Coastguard Worker    def test_binary_finder(self):
409*288bf522SAndroid Build Coastguard Worker        # Create binary_cache.
410*288bf522SAndroid Build Coastguard Worker        binary_cache_builder = BinaryCacheBuilder(TestHelper.ndk_path, False)
411*288bf522SAndroid Build Coastguard Worker        elf_name = 'simpleperf_runtest_two_functions_arm'
412*288bf522SAndroid Build Coastguard Worker        elf_path = TestHelper.testdata_path(elf_name)
413*288bf522SAndroid Build Coastguard Worker        readelf = ReadElf(TestHelper.ndk_path)
414*288bf522SAndroid Build Coastguard Worker        build_id = readelf.get_build_id(elf_path)
415*288bf522SAndroid Build Coastguard Worker        self.assertGreater(len(build_id), 0)
416*288bf522SAndroid Build Coastguard Worker        binary_cache_builder.binaries[elf_name] = build_id
417*288bf522SAndroid Build Coastguard Worker
418*288bf522SAndroid Build Coastguard Worker        filename_without_build_id = '/data/symfs_without_build_id/elf'
419*288bf522SAndroid Build Coastguard Worker        binary_cache_builder.binaries[filename_without_build_id] = ''
420*288bf522SAndroid Build Coastguard Worker
421*288bf522SAndroid Build Coastguard Worker        binary_cache_builder.copy_binaries_from_symfs_dirs([TestHelper.testdata_dir])
422*288bf522SAndroid Build Coastguard Worker        binary_cache_builder.create_build_id_list()
423*288bf522SAndroid Build Coastguard Worker
424*288bf522SAndroid Build Coastguard Worker        # Test BinaryFinder.
425*288bf522SAndroid Build Coastguard Worker        path_in_binary_cache = binary_cache_builder.find_path_in_cache(elf_name)
426*288bf522SAndroid Build Coastguard Worker        binary_finder = BinaryFinder(binary_cache_builder.binary_cache_dir, readelf)
427*288bf522SAndroid Build Coastguard Worker        # Find binary using build id.
428*288bf522SAndroid Build Coastguard Worker        path = binary_finder.find_binary('[not_exist_file]', build_id)
429*288bf522SAndroid Build Coastguard Worker        self.assertEqual(path, path_in_binary_cache)
430*288bf522SAndroid Build Coastguard Worker        # Find binary using path.
431*288bf522SAndroid Build Coastguard Worker        path = binary_finder.find_binary(filename_without_build_id, None)
432*288bf522SAndroid Build Coastguard Worker        self.assertIsNotNone(path)
433*288bf522SAndroid Build Coastguard Worker        # Find binary using absolute path.
434*288bf522SAndroid Build Coastguard Worker        path = binary_finder.find_binary(str(path_in_binary_cache), None)
435*288bf522SAndroid Build Coastguard Worker        self.assertEqual(path, path_in_binary_cache)
436*288bf522SAndroid Build Coastguard Worker
437*288bf522SAndroid Build Coastguard Worker        # The binary should has a matched build id.
438*288bf522SAndroid Build Coastguard Worker        path = binary_finder.find_binary('/' + elf_name, 'wrong_build_id')
439*288bf522SAndroid Build Coastguard Worker        self.assertIsNone(path)
440