| #!/usr/bin/env python3 |
| # Copyright 2021 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import unittest |
| |
| import dwarfdump |
| |
| |
| class DwarfDumpTest(unittest.TestCase): |
| def _MakeRangeInfoList(self, flat_list): |
| out = [] |
| for item in flat_list: |
| assert len(item) == 3 |
| out.append((dwarfdump._AddressRange(item[0], item[1]), item[2])) |
| return out |
| |
| def testParseNonContiguousAddressRange(self): |
| """Test parsing DW_TAG_compile_unit with non-contiguous address range.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("solution.cc")', |
| 'DW_AT_low_pc (0x0)', |
| 'DW_AT_ranges (0x1', |
| '[0x10, 0x21)', |
| '[0x31, 0x41))', |
| ] |
| expected_info_list = [(0x10, 0x21, 'solution.cc'), |
| (0x31, 0x41, 'solution.cc')] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testParseNonContiguousAddressRangeOtherBrackets(self): |
| """Test parsing DW_AT_ranges when non-standard brackets are used.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("solution.cc")', |
| 'DW_AT_low_pc (0x0)', |
| 'DW_AT_ranges [0x1', |
| '(0x10, 0x21)', |
| '[0x31, 0x41]]', |
| ] |
| expected_info_list = [(0x10, 0x21, 'solution.cc'), |
| (0x31, 0x41, 'solution.cc')] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testParseNonContiguousIgnoreEmptyRanges(self): |
| """Test that empty ranges are ignored when parsing DW_AT_ranges.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("solution.cc")', |
| 'DW_AT_ranges (0x1', |
| '[0x1, 0x1)', |
| '[0x10, 0x21)', |
| '[0x22, 0x22)', |
| '[0x31, 0x41)', |
| '[0x42, 0x42))', |
| ] |
| expected_info_list = [(0x10, 0x21, 'solution.cc'), |
| (0x31, 0x41, 'solution.cc')] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testParseContiguousAddressRange(self): |
| """Test parsing DW_TAG_compile_unit with contiguous address range.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("solution.cc")', |
| 'DW_AT_low_pc (0x1)', |
| 'DW_AT_high_pc (0x10)', |
| ] |
| expected_info_list = [ |
| (0x1, 0x10, 'solution.cc'), |
| ] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testParseSingleAddress(self): |
| """Test parsing DW_TAG_compile_unit with single address.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("solution.cc")', |
| 'DW_AT_low_pc (0x10)', |
| ] |
| expected_info_list = [ |
| (0x10, 0x11, 'solution.cc'), |
| ] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testParseEmptyCompileUnit(self): |
| """Test parsing empty DW_TAG_compile_unit.""" |
| lines = ['DW_TAG_compile_unit'] |
| self.assertEqual([], dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testConsecutiveCompileUnits(self): |
| """Test parsing consecutive DW_TAG_compile_units.""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("foo.cc")', |
| 'DW_AT_low_pc (0x1)', |
| 'DW_AT_high_pc (0x10)', |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("bar.cc")', |
| 'DW_AT_low_pc (0x12)', |
| 'DW_AT_high_pc (0x20)', |
| ] |
| expected_info_list = [(0x1, 0x10, 'foo.cc'), (0x12, 0x20, 'bar.cc')] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testTagTerminatedCompileUnit(self): |
| """Test parsing DW_TAG_compile_unit where compile unit is followed by a |
| non-DW_TAG_compile_unit entry. |
| """ |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("foo.cc")', |
| 'DW_AT_low_pc (0x1)', |
| 'DW_AT_high_pc (0x10)', |
| 'DW_TAG_subprogram', |
| 'DW_AT_name ("bar.cc")', |
| 'DW_AT_low_pc (0x12)', |
| 'DW_AT_high_pc (0x20)', |
| ] |
| expected_info_list = [ |
| (0x1, 0x10, 'foo.cc'), |
| ] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testHandlePrefixes(self): |
| """Test parsing DW_TAG_compile_unit where 'DW_' does not start line in |
| DW_TAG_compile_unit entry. |
| """ |
| lines = [ |
| '0x1 DW_TAG_compile_unit', |
| ' DW_AT_language (DW_LANG_C_plus_plus_14)', |
| ' DW_AT_name ("solution.cc")', |
| ' DW_AT_stmt_list (0x5)', |
| ' DW_AT_low_pc (0x1)', |
| ' DW_AT_high_pc (0x10)', |
| ] |
| expected_info_list = [ |
| (0x1, 0x10, 'solution.cc'), |
| ] |
| self.assertEqual(self._MakeRangeInfoList(expected_info_list), |
| dwarfdump.ParseDumpOutputForTest(lines)) |
| |
| def testFindAddress(self): |
| """Tests for _SourceMapper.FindSourceForTextAddress()""" |
| lines = [ |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("foo.cc")', |
| 'DW_AT_low_pc (0x1)', |
| 'DW_AT_high_pc (0x10)', |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("bar.cc")', |
| 'DW_AT_low_pc (0x21)', |
| 'DW_AT_high_pc (0x30)', |
| 'DW_TAG_compile_unit', |
| 'DW_AT_name ("baz.cc")', |
| 'DW_AT_low_pc (0x41)', |
| 'DW_AT_high_pc (0x50)', |
| ] |
| source_mapper = dwarfdump.CreateAddressSourceMapperForTest(lines) |
| # Address is before first range. |
| self.assertEqual('', source_mapper.FindSourceForTextAddress(0x0)) |
| # Address matches start of first range. |
| self.assertEqual('foo.cc', source_mapper.FindSourceForTextAddress(0x1)) |
| # Address is in the middle of middle range. |
| self.assertEqual('bar.cc', source_mapper.FindSourceForTextAddress(0x2a)) |
| # Address matches end of last range. |
| self.assertEqual('baz.cc', source_mapper.FindSourceForTextAddress(0x4f)) |
| # Address is after lange range. |
| self.assertEqual('', source_mapper.FindSourceForTextAddress(0x50)) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |