| #!/usr/bin/env vpython3 |
| # Copyright 2015 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import tempfile |
| import unittest |
| |
| import symbol_extractor |
| |
| |
| # The number of spaces that objdump prefixes each symbol with. |
| SPACES = ' ' * 14 |
| |
| class TestSymbolInfosFromStream(unittest.TestCase): |
| |
| SYMBOL_INFO_DUMP = r"""[ |
| { |
| "FileSummary": { |
| "File": "./exe.unstripped/chrome_crashpad_handler", |
| "Format": "elf64-littleaarch64", |
| "Arch": "aarch64", |
| "AddressSize": "64bit", |
| "LoadName": "<Not found>" |
| }, |
| "Symbols": [ |
| { |
| "Symbol": { |
| "Name": { |
| "Name": "", |
| "Value": 0 |
| }, |
| "Value": 0, |
| "Size": 0, |
| "Binding": { |
| "Name": "Local", |
| "Value": 0 |
| }, |
| "Type": { |
| "Name": "None", |
| "Value": 0 |
| }, |
| "Other": { |
| "Value": 0, |
| "Flags": [] |
| }, |
| "Section": { |
| "Name": "Undefined", |
| "Value": 0 |
| } |
| } |
| }, |
| { |
| "Symbol": { |
| "Name": { |
| "Name": "first", |
| "Value": 42 |
| }, |
| "Value": 12697692, |
| "Size": 44, |
| "Binding": { |
| "Name": "Local", |
| "Value": 2 |
| }, |
| "Type": { |
| "Name": "Function", |
| "Value": 4 |
| }, |
| "Other": { |
| "Value": 0, |
| "Flags": [] |
| }, |
| "Section": { |
| "Name": ".text", |
| "Value": 65521 |
| } |
| } |
| }, |
| { |
| "Symbol": { |
| "Name": { |
| "Name": "second", |
| "Value": 42 |
| }, |
| "Value": 341, |
| "Size": 18, |
| "Binding": { |
| "Name": "Global", |
| "Value": 2 |
| }, |
| "Type": { |
| "Name": "Function", |
| "Value": 4 |
| }, |
| "Other": { |
| "Value": 0, |
| "Flags": [] |
| }, |
| "Section": { |
| "Name": ".text", |
| "Value": 65521 |
| } |
| } |
| }, |
| { |
| "Symbol": { |
| "Name": { |
| "Name": "third", |
| "Value": 53234419 |
| }, |
| "Value": 83614392, |
| "Size": 80, |
| "Binding": { |
| "Name": "Local", |
| "Value": 0 |
| }, |
| "Type": { |
| "Name": "GNU_IFunc", |
| "Value": 10 |
| }, |
| "Other": { |
| "Value": 2, |
| "Flags": [ |
| { |
| "Name": "STV_HIDDEN", |
| "Value": 2 |
| } |
| ] |
| }, |
| "Section": { |
| "Name": ".text", |
| "Value": 16 |
| } |
| } |
| }, |
| { |
| "Symbol": { |
| "Name": { |
| "Name": "do_not_parse", |
| "Value": 1216 |
| }, |
| "Value": 39499768, |
| "Size": 80, |
| "Binding": { |
| "Name": "Local", |
| "Value": 0 |
| }, |
| "Type": { |
| "Name": "None", |
| "Value": 0 |
| }, |
| "Other": { |
| "Value": 0, |
| "Flags": [] |
| }, |
| "Section": { |
| "Name": ".text", |
| "Value": 16 |
| } |
| } |
| } |
| ] |
| } |
| ]""" |
| |
| def testSymbolInfosFromStream(self): |
| with tempfile.TemporaryFile(suffix='.json') as fp: |
| fp.write(self.SYMBOL_INFO_DUMP.encode('utf8')) |
| fp.seek(0) |
| symbol_infos = symbol_extractor._SymbolInfosFromStream(fp) |
| self.assertEquals(len(symbol_infos), 3) |
| first = symbol_extractor.SymbolInfo('first', 0x00c1c05c, 0x2c, '.text') |
| self.assertEquals(first, symbol_infos[0]) |
| second = symbol_extractor.SymbolInfo('second', 0x00155, 0x12, '.text') |
| self.assertEquals(second, symbol_infos[1]) |
| third = symbol_extractor.SymbolInfo('third', 0x4fbdab8, 0x50, '.text') |
| self.assertEquals(third, symbol_infos[2]) |
| |
| |
| class TestSymbolInfoMappings(unittest.TestCase): |
| |
| def setUp(self): |
| self.symbol_infos = [ |
| symbol_extractor.SymbolInfo('firstNameAtOffset', 0x42, 42, '.text'), |
| symbol_extractor.SymbolInfo('secondNameAtOffset', 0x42, 42, '.text'), |
| symbol_extractor.SymbolInfo('thirdSymbol', 0x64, 20, '.text')] |
| |
| def testGroupSymbolInfosByOffset(self): |
| offset_to_symbol_info = symbol_extractor.GroupSymbolInfosByOffset( |
| self.symbol_infos) |
| self.assertEquals(len(offset_to_symbol_info), 2) |
| self.assertIn(0x42, offset_to_symbol_info) |
| self.assertEquals(offset_to_symbol_info[0x42][0], self.symbol_infos[0]) |
| self.assertEquals(offset_to_symbol_info[0x42][1], self.symbol_infos[1]) |
| self.assertIn(0x64, offset_to_symbol_info) |
| self.assertEquals(offset_to_symbol_info[0x64][0], self.symbol_infos[2]) |
| |
| def testCreateNameToSymbolInfo(self): |
| name_to_symbol_info = symbol_extractor.CreateNameToSymbolInfo( |
| self.symbol_infos) |
| self.assertEquals(len(name_to_symbol_info), 3) |
| for i in range(3): |
| name = self.symbol_infos[i].name |
| self.assertIn(name, name_to_symbol_info) |
| self.assertEquals(self.symbol_infos[i], name_to_symbol_info[name]) |
| |
| def testSymbolCollisions(self): |
| symbol_infos_with_collision = list(self.symbol_infos) |
| symbol_infos_with_collision.append(symbol_extractor.SymbolInfo( |
| 'secondNameAtOffset', 0x84, 42, '.text')) |
| |
| # The symbol added above should not affect the output. |
| name_to_symbol_info = symbol_extractor.CreateNameToSymbolInfo( |
| self.symbol_infos) |
| self.assertEquals(len(name_to_symbol_info), 3) |
| for i in range(3): |
| name = self.symbol_infos[i].name |
| self.assertIn(name, name_to_symbol_info) |
| self.assertEquals(self.symbol_infos[i], name_to_symbol_info[name]) |
| |
| if __name__ == '__main__': |
| unittest.main() |