summaryrefslogtreecommitdiffstats
path: root/tools/cygprofile/symbol_extractor_unittest.py
blob: bd2db4a356cbe09759ce03d8d9115ab5bbedbb3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/python
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import symbol_extractor
import unittest

class TestSymbolInfo(unittest.TestCase):
  def testIgnoresBlankLine(self):
    symbol_info = symbol_extractor._FromObjdumpLine('')
    self.assertIsNone(symbol_info)

  def testIgnoresMalformedLine(self):
    # This line is too short.
    line = ('00c1b228      F .text  00000060 _ZN20trace_event')
    symbol_info = symbol_extractor._FromObjdumpLine(line)
    self.assertIsNone(symbol_info)
    # This line has the wrong marker.
    line = '00c1b228 l     f .text  00000060 _ZN20trace_event'
    symbol_info = symbol_extractor._FromObjdumpLine(line)
    self.assertIsNone(symbol_info)

  def testAssertionErrorOnInvalidLines(self):
    # This line has an invalid scope.
    line = ('00c1b228 z     F .text  00000060 _ZN20trace_event')
    self.assertRaises(AssertionError, symbol_extractor._FromObjdumpLine, line)
    # This line has too many fields.
    line = ('00c1b228 l     F .text  00000060 _ZN20trace_event too many')
    self.assertRaises(AssertionError, symbol_extractor._FromObjdumpLine, line)
    # This line has invalid characters in the symbol.
    line = ('00c1b228 l     F .text  00000060 _ZN20trace_?bad')
    self.assertRaises(AssertionError, symbol_extractor._FromObjdumpLine, line)
    # This line has an invalid character at the start of the symbol name.
    line = ('00c1b228 l     F .text  00000060 $_ZN20trace_bad')
    self.assertRaises(AssertionError, symbol_extractor._FromObjdumpLine, line)

  def testSymbolInfo(self):
    line = ('00c1c05c l     F .text  0000002c '
            '_GLOBAL__sub_I_chrome_main_delegate.cc')
    test_name = '_GLOBAL__sub_I_chrome_main_delegate.cc'
    test_offset = 0x00c1c05c
    test_size = 0x2c
    test_section = '.text'
    symbol_info = symbol_extractor._FromObjdumpLine(line)
    self.assertIsNotNone(symbol_info)
    self.assertEquals(test_offset, symbol_info.offset)
    self.assertEquals(test_size, symbol_info.size)
    self.assertEquals(test_name, symbol_info.name)
    self.assertEquals(test_section, symbol_info.section)

  def testHiddenSymbol(self):
    line = ('00c1c05c l     F .text  0000002c '
            '.hidden _GLOBAL__sub_I_chrome_main_delegate.cc')
    test_name = '_GLOBAL__sub_I_chrome_main_delegate.cc'
    test_offset = 0x00c1c05c
    test_size = 0x2c
    test_section = '.text'
    symbol_info = symbol_extractor._FromObjdumpLine(line)
    self.assertIsNotNone(symbol_info)
    self.assertEquals(test_offset, symbol_info.offset)
    self.assertEquals(test_size, symbol_info.size)
    self.assertEquals(test_name, symbol_info.name)
    self.assertEquals(test_section, symbol_info.section)

  def testDollarInSymbolName(self):
    # A $ character elsewhere in the symbol name is fine.
    # This is an example of a lambda function name from Clang.
    line = ('00c1b228 l     F .text  00000060 _ZZL11get_globalsvENK3$_1clEv')
    symbol_info = symbol_extractor._FromObjdumpLine(line)
    self.assertIsNotNone(symbol_info)
    self.assertEquals(0xc1b228, symbol_info.offset)
    self.assertEquals(0x60, symbol_info.size)
    self.assertEquals('_ZZL11get_globalsvENK3$_1clEv', symbol_info.name)
    self.assertEquals('.text', symbol_info.section)


class TestSymbolInfosFromStream(unittest.TestCase):
  def testSymbolInfosFromStream(self):
    lines = ['Garbage',
             '',
             '00c1c05c l     F .text  0000002c first',
             ''
             'more garbage',
             '00155 g     F .text  00000012 second']
    symbol_infos = symbol_extractor._SymbolInfosFromStream(lines)
    self.assertEquals(len(symbol_infos), 2)
    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])


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()