# Copyright 2021 The Pigweed Authors # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. """Tests for pw_symbolizer's llvm-symbolizer based symbolization.""" import subprocess import tempfile import unittest import json from pathlib import Path import pw_symbolizer _MODULE_PY_DIR = Path(__file__).parent.resolve() _CPP_TEST_FILE_NAME = 'symbolizer_test.cc' _COMPILER = 'clang++' class TestSymbolizer(unittest.TestCase): """Unit tests for binary symbolization.""" def _test_symbolization_results(self, expected_symbols, symbolizer): for expected_symbol in expected_symbols: result = symbolizer.symbolize(expected_symbol['Address']) self.assertEqual(result.name, expected_symbol['Expected']) self.assertEqual(result.address, expected_symbol['Address']) # Objects sometimes don't have a file/line number for some # reason. if not expected_symbol['IsObj']: self.assertEqual(result.file, _CPP_TEST_FILE_NAME) self.assertEqual(result.line, expected_symbol['Line']) def test_symbolization(self): """Tests that the symbolizer can symbolize addresses properly.""" with tempfile.TemporaryDirectory() as exe_dir: exe_file = Path(exe_dir) / 'print_expected_symbols' # Compiles a binary that prints symbol addresses and expected # results as JSON. cmd = [ _COMPILER, _CPP_TEST_FILE_NAME, '-gfull', f'-ffile-prefix-map={_MODULE_PY_DIR}=', '-std=c++17', '-o', exe_file, ] process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=_MODULE_PY_DIR) self.assertEqual(process.returncode, 0) process = subprocess.run([exe_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) self.assertEqual(process.returncode, 0) expected_symbols = [ json.loads(line) for line in process.stdout.decode().splitlines() ] symbolizer = pw_symbolizer.LlvmSymbolizer(exe_file) self._test_symbolization_results(expected_symbols, symbolizer) # Test backwards compatibility with older versions of # llvm-symbolizer. symbolizer = pw_symbolizer.LlvmSymbolizer(exe_file, force_legacy=True) self._test_symbolization_results(expected_symbols, symbolizer) if __name__ == '__main__': unittest.main()