1# Copyright 2021 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Tests for pw_symbolizer's llvm-symbolizer based symbolization.""" 15 16import subprocess 17import tempfile 18import unittest 19import json 20from pathlib import Path 21import pw_symbolizer 22 23_MODULE_PY_DIR = Path(__file__).parent.resolve() 24_CPP_TEST_FILE_NAME = 'symbolizer_test.cc' 25 26_COMPILER = 'clang++' 27 28 29class TestSymbolizer(unittest.TestCase): 30 """Unit tests for binary symbolization.""" 31 def _test_symbolization_results(self, expected_symbols, symbolizer): 32 for expected_symbol in expected_symbols: 33 result = symbolizer.symbolize(expected_symbol['Address']) 34 self.assertEqual(result.name, expected_symbol['Expected']) 35 self.assertEqual(result.address, expected_symbol['Address']) 36 37 # Objects sometimes don't have a file/line number for some 38 # reason. 39 if not expected_symbol['IsObj']: 40 self.assertEqual(result.file, _CPP_TEST_FILE_NAME) 41 self.assertEqual(result.line, expected_symbol['Line']) 42 43 def test_symbolization(self): 44 """Tests that the symbolizer can symbolize addresses properly.""" 45 with tempfile.TemporaryDirectory() as exe_dir: 46 exe_file = Path(exe_dir) / 'print_expected_symbols' 47 48 # Compiles a binary that prints symbol addresses and expected 49 # results as JSON. 50 cmd = [ 51 _COMPILER, 52 _CPP_TEST_FILE_NAME, 53 '-gfull', 54 f'-ffile-prefix-map={_MODULE_PY_DIR}=', 55 '-std=c++17', 56 '-o', 57 exe_file, 58 ] 59 60 process = subprocess.run(cmd, 61 stdout=subprocess.PIPE, 62 stderr=subprocess.STDOUT, 63 cwd=_MODULE_PY_DIR) 64 self.assertEqual(process.returncode, 0) 65 66 process = subprocess.run([exe_file], 67 stdout=subprocess.PIPE, 68 stderr=subprocess.STDOUT) 69 self.assertEqual(process.returncode, 0) 70 71 expected_symbols = [ 72 json.loads(line) 73 for line in process.stdout.decode().splitlines() 74 ] 75 76 symbolizer = pw_symbolizer.LlvmSymbolizer(exe_file) 77 self._test_symbolization_results(expected_symbols, symbolizer) 78 79 # Test backwards compatibility with older versions of 80 # llvm-symbolizer. 81 symbolizer = pw_symbolizer.LlvmSymbolizer(exe_file, 82 force_legacy=True) 83 self._test_symbolization_results(expected_symbols, symbolizer) 84 85 86if __name__ == '__main__': 87 unittest.main() 88