Skip to content

Commit

Permalink
Bug in identifying the name field in gprof output
Browse files Browse the repository at this point in the history
The field containing the name of the function and
the file containing the function in a line from
the gprof call graph begins at column 46 for line
that represents the function in question. However,
for its callers and callees the field begins at
column 50. Change adds code to differentiate the
types of lines when substringing.

Change fixed #46
  • Loading branch information
nuthanmunaiah committed Jul 27, 2015
1 parent 6ccaaa9 commit 79f115e
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 40 deletions.
10 changes: 7 additions & 3 deletions attacksurfacemeter/loaders/gprof_line_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ def load(self, gprof_line):
self.__init__()

# The field in the gprof call graph that contains the name of the
# function and the file containing the function begins at column 46
# (deduced from gprof source code)
name = gprof_line[45:]
# function and the file containing the function begins at column 46
# for the function in question and at column 50 for its callers and
# callees
# Source: Deduced gprof source code
name = gprof_line[49:]
if gprof_line.startswith('['):
name = gprof_line[45:]
match = RE_NAME.match(name.strip())

if match:
Expand Down
116 changes: 79 additions & 37 deletions tests/test_gprof_line_parser.py
Original file line number Diff line number Diff line change
@@ -1,153 +1,195 @@
__author__ = 'kevin'

import unittest
from attacksurfacemeter.loaders.gprof_line_parser import GprofLineParser


class GprofLineParserTestCase(unittest.TestCase):

def test_get_function_name_entry(self):
# Arrange
test_line_parser = GprofLineParser.get_instance("[4] 0.0 0.00 0.00 2 greet (greetings.c:38 @ 581033) [4]")
test_line_parser = GprofLineParser.get_instance(
'[4] 0.0 0.00 0.00 2 greet '
'(greetings.c:38 @ 581033) [4]'
)

# Act
test_function_name = test_line_parser.get_function_name()

# Assert
self.assertEqual("greet", test_function_name)
self.assertEqual('greet', test_function_name)

def test_get_function_signature_entry(self):
# Arrange
test_line_parser = GprofLineParser.get_instance("[4] 0.0 0.00 0.00 2 greet (greetings.c:38 @ 581033) [4]")
test_line_parser = GprofLineParser.get_instance(
'[4] 0.0 0.00 0.00 2 greet '
'(greetings.c:38 @ 581033) [4]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("greetings.c", test_function_signature)
self.assertEqual('greetings.c', test_function_signature)

def test_get_function_name_with_self_and_children(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(" 0.00 0.00 1/2 greet_b (helloworld.c:38 @ 581033) [9]")
test_line_parser = GprofLineParser.get_instance(
' 0.00 0.00 1/2 greet_b '
'(helloworld.c:38 @ 581033) [9]'
)

# Act
test_function_name = test_line_parser.get_function_name()

# Assert
self.assertEqual("greet_b", test_function_name)
self.assertEqual('greet_b', test_function_name)

def test_get_function_signature_with_self_and_children(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(" 0.00 0.00 1/2 greet_b (helloworld.c:38 @ 581033) [9]")
test_line_parser = GprofLineParser.get_instance(
' 0.00 0.00 1/2 greet_b '
'(helloworld.c:38 @ 581033) [9]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("helloworld.c", test_function_signature)
self.assertEqual('helloworld.c', test_function_signature)

def test_get_function_name_with_called_only(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(" 8 recursive_a <cycle 1> (greetings.c:38 @ 581033) [3]")
test_line_parser = GprofLineParser.get_instance(
' 8 '
'recursive_a <cycle 1> (greetings.c:38 @ 581033) [3]'
)

# Act
test_function_name = test_line_parser.get_function_name()

# Assert
self.assertEqual("recursive_a", test_function_name)
self.assertEqual('recursive_a', test_function_name)

def test_get_function_signature_with_called_only(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(" 8 recursive_a <cycle 1> (greetings.c:38 @ 581033) [3]")
test_line_parser = GprofLineParser.get_instance(
' 8 '
'recursive_a <cycle 1> (greetings.c:38 @ 581033) [3]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("greetings.c", test_function_signature)
self.assertEqual('greetings.c', test_function_signature)

def test_spontaneous(self):
# Assert
self.assertRaises(ValueError, GprofLineParser.get_instance,
" <spontaneous>")
self.assertRaises(
ValueError, GprofLineParser.get_instance,
' <spontaneous>'
)

def test_get_function_signature_with_path(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(
"[12] 0.0 0.00 0.00 72000 hScale_MMX "
"(./libswscale/x86/swscale_template.c:1921 @ 9f46e0) [12]"
'[12] 0.0 0.00 0.00 72000 hScale_MMX '
'(./libswscale/x86/swscale_template.c:1921 @ 9f46e0) [12]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("./libswscale/x86/swscale_template.c", test_function_signature)
self.assertEqual(
'./libswscale/x86/swscale_template.c', test_function_signature
)

# Arrange
test_line_parser = GprofLineParser.get_instance(
" 0.00 0.00 2590/5180 opt_find "
"(./libavcodec/options.c:53 @ 77e710) [316705]"
' 0.00 0.00 2590/5180 opt_find '
'(./libavcodec/options.c:53 @ 77e710) [316705]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("./libavcodec/options.c", test_function_signature)
self.assertEqual('./libavcodec/options.c', test_function_signature)

# Arrange
test_line_parser = GprofLineParser.get_instance(
"[49220 0.0 0.00 0.00 "
"__do_global_ctors_aux [492203]"
'[49220 0.0 0.00 0.00 '
'__do_global_ctors_aux [492203]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("", test_function_signature)
self.assertEqual('', test_function_signature)

def test_get_function_signature_include_files(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(
" 0.00 0.00 1/34841 snprintf "
"(/usr/include/x86_64-linux-gnu/bits/stdio2.h:64 @ 47d37b) "
"[650457]"
' 0.00 0.00 1/34841 snprintf '
'(/usr/include/x86_64-linux-gnu/bits/stdio2.h:64 @ 47d37b) '
'[650457]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("/usr/include/x86_64-linux-gnu/bits/stdio2.h",
test_function_signature)
self.assertEqual(
'/usr/include/x86_64-linux-gnu/bits/stdio2.h',
test_function_signature
)

# Arrange
test_line_parser = GprofLineParser.get_instance(
" 0.00 0.00 1/589 atoi "
"(/usr/include/stdlib.h:280 @ 57c1fc) [26713]"
' 0.00 0.00 1/589 atoi '
'(/usr/include/stdlib.h:280 @ 57c1fc) [26713]'
)

# Act
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("/usr/include/stdlib.h", test_function_signature)
self.assertEqual('/usr/include/stdlib.h', test_function_signature)

def test_load_recursive_call_line(self):
# Arrange
test_line_parser = GprofLineParser.get_instance(
"[86901 0.0 0.00 0.00 12+12 _init [869011]"
'[86901 0.0 0.00 0.00 12+12 _init [869011]'
)

# Act
test_function_name = test_line_parser.get_function_name()
test_function_signature = test_line_parser.get_function_signature()

# Assert
self.assertEqual("_init", test_function_name)
self.assertEqual("", test_function_signature)
self.assertEqual('_init', test_function_name)
self.assertEqual('', test_function_signature)

def test_issue_46(self):
'''Unit test to test the fix for issue #46.
Specifics:
https://github.com/andymeneely/attack-surface-metrics/issues/46
'''
# Arrange
line = (
' 0.00 0.00 11361600/11361600 '
'ff_h264_decode_mb_cabac (./libavcodec/h264_cabac.c:'
'2141 @ cfeb13) [6]'
)
expected = 'ff_h264_decode_mb_cabac'

# Act
target = GprofLineParser.get_instance(line)
actual = target.get_function_name()

# Assert
self.assertEqual(expected, actual)

if __name__ == '__main__':
unittest.main()

0 comments on commit 79f115e

Please sign in to comment.