def _load_call_graph(self, index, granularity, sync_queue): loader = GprofLoader( self.sources[index], self.is_reverse, self.defenses, self.vulnerabilities ) call_graph = loader.load_call_graph(granularity) sync_queue.put((call_graph, loader.errors), block=True)
def setUp(self): self.target = GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'ffmpeg/gprof.callgraph.txt' ), False )
def test_load_call_graph_empty_file(self): # Act target = GprofLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld/empty.gprof.callgraph.txt'), False) # Using a separate process to ensure the loading of an emtpy call graph # completes within a reasonable time (see timeout below). queue = multiprocessing.Queue() process = multiprocessing.Process(name='p.gprof', target=self._wrapper, args=(target.load_call_graph, queue)) process.start() timeout = 1 process.join(timeout=timeout) is_alive = process.is_alive() if is_alive: process.terminate() self.assertFalse( is_alive, msg=('Process loading an empty gprof file has not terminated' ' even after {0} second(s).'.format(timeout))) # Assert test_graph = queue.get() self.assertEqual(0, len(test_graph.nodes()))
def load_call_graph(self): """ Generates a Call Graph as a networkx.DiGraph object. The call graph generated is an aggregate of multiple call graphs output by GNU gprof. """ call_graph = None for source in self.sources: _gprof_loader = GprofLoader(source, reverse=self.reverse) _gprof_call_graph = _gprof_loader.load_call_graph() if call_graph: call_graph.add_edges_from( _gprof_call_graph.edges() ) else: call_graph = _gprof_call_graph self.error_messages.append(_gprof_loader.error_messages) return call_graph
def setUp(self): self.target = CallGraph.from_merge( CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.txt' ), True ) ), CallGraph.from_loader( GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt' ) ) ) )
class GprofLoaderFFmpegFileTestCase(unittest.TestCase): def setUp(self): self.target = GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'ffmpeg/gprof.callgraph.txt' ), False ) def test_load_call_graph_errors(self): # Act graph = self.target.load_call_graph() # Assert self.assertEqual(1, len(self.target.errors)) def test_load_call_graph_nodes(self): # Arrange expected = [ Call('opt_progress', './ffmpeg_opt.c', Environments.C), Call('get_preset_file_2', './ffmpeg_opt.c', Environments.C), Call('dump_attachment', './ffmpeg_opt.c', Environments.C), Call('open_output_file', './ffmpeg_opt.c', Environments.C), Call('init_input', './libavformat/utils.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('ffurl_open', './libavformat/avio.c', Environments.C), Call('biquad_s16', './libavfilter/af_biquads.c', Environments.C), Call('av_log', './libavutil/log.c', Environments.C) ] # Act graph = self.target.load_call_graph() actual = graph.nodes() # Assert self.assertCountEqual(expected, actual) for (_, attrs) in graph.nodes(data=True): self.assertTrue('tested' in attrs) self.assertTrue('defense' not in attrs) self.assertTrue('dangerous' not in attrs) self.assertTrue('vulnerable' not in attrs) def test_load_call_graph_entry_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('entry' in attrs) else: self.assertTrue('entry' not in attrs) def test_load_call_graph_exit_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('exit' in attrs) else: self.assertTrue('exit' not in attrs) def test_load_call_graph_edges(self): # Arrange expected = [ ( Call('opt_progress', './ffmpeg_opt.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('opt_progress', './ffmpeg_opt.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('get_preset_file_2', './ffmpeg_opt.c', Environments.C) ), ( Call('get_preset_file_2', './ffmpeg_opt.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call('dump_attachment', './ffmpeg_opt.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('dump_attachment', './ffmpeg_opt.c', Environments.C) ), ( Call('open_output_file', './ffmpeg_opt.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('open_output_file', './ffmpeg_opt.c', Environments.C) ), ( Call('init_input', './libavformat/utils.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('init_input', './libavformat/utils.c', Environments.C) ), ( Call('avio_open2', './libavformat/aviobuf.c', Environments.C), Call('ffurl_open', './libavformat/avio.c', Environments.C) ), ( Call('ffurl_open', './libavformat/avio.c', Environments.C), Call('avio_open2', './libavformat/aviobuf.c', Environments.C) ), ( Call( 'biquad_s16', './libavfilter/af_biquads.c', Environments.C ), Call('av_log', './libavutil/log.c', Environments.C) ), ( Call('av_log', './libavutil/log.c', Environments.C), Call( 'biquad_s16', './libavfilter/af_biquads.c', Environments.C ) ), ] # Act graph = self.target.load_call_graph() actual = graph.edges() # Assert self.assertCountEqual(expected, actual) for (_, _, attrs) in graph.edges(data=True): self.assertTrue('gprof' in attrs) self.assertTrue('cflow' not in attrs) self.assertTrue('call' in attrs or 'return' in attrs) def test_load_call_graph_return_edges(self): # Act graph = self.target.load_call_graph() # Assert for (u, v) in nx.get_edge_attributes(graph, 'call'): self.assertTrue('return' in graph[v][u])
def test_fix(self): # Arrange target = CallGraph.from_loader( CflowLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/cflow.callgraph.r.mod.txt' ), True ) ) _target = copy.deepcopy(target) reference = CallGraph.from_loader( GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt' ) ) ) expected = { 'before': Call('GreeterSayHi', '', Environments.C), 'after': Call('GreeterSayHi', './src/helloworld.c', Environments.C) } # Act utilities.fix(target, using=reference) actual = { 'before': next( i for (i, _) in _target.nodes if i.function_name == 'GreeterSayHi' ), 'after': next( i for (i, _) in target.nodes if i.function_name == 'GreeterSayHi' ) } # Assert self.assertEqual(expected['before'], actual['before']) self.assertEqual(expected['after'], actual['after']) # Asserting if node attributes got carried over self.assertCountEqual( [ attrs for (i, attrs) in _target.nodes if i == expected['before'] ], [ attrs for (i, attrs) in target.nodes if i == expected['after'] ] ) # Asserting if edge attributes got carried over self.assertCountEqual( [ attrs for (i, j, attrs) in _target.edges if i == expected['before'] or j == expected['before'] ], [ attrs for (i, j, attrs) in target.edges if i == expected['after'] or j == expected['after'] ], ) # Asserting if OTHER nodes and their attributes got carried over self.assertCountEqual( [ (i, attrs) for (i, attrs) in _target.nodes if i != expected['before'] ], [ (i, attrs) for (i, attrs) in target.nodes if i != expected['after'] ] ) # Asserting if OTHER edges and their attributes got carried over self.assertCountEqual( [ (i, j, attrs) for (i, j, attrs) in _target.edges if i != expected['before'] and j != expected['before'] ], [ (i, j, attrs) for (i, j, attrs) in target.edges if i != expected['after'] and j != expected['after'] ], )
class GprofLoaderTestCase(unittest.TestCase): def setUp(self): self.target = GprofLoader( os.path.join( os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt' ), False ) def test_load_call_graph_errors(self): # Act graph = self.target.load_call_graph() # Assert self.assertEqual(0, len(self.target.errors)) def test_load_call_graph_nodes(self): # Arrange expected = [ Call('GreeterSayHiTo', './src/helloworld.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C), Call('new_Greeter', './src/helloworld.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C), Call('addInt', './src/helloworld.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHi', './src/helloworld.c', Env.C) ] # Act graph = self.target.load_call_graph() actual = graph.nodes() match = ( all([i in actual for i in expected]) and all([i in expected for i in actual]) ) # Assert self.assertCountEqual(expected, actual) for (_, attrs) in graph.nodes(data=True): self.assertTrue('tested' in attrs) self.assertTrue('defense' not in attrs) self.assertTrue('dangerous' not in attrs) self.assertTrue('vulnerable' not in attrs) def test_load_call_graph_nodes_file_granularity(self): # Arrange expected = [ Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE) ] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) actual = graph.nodes() match = ( all([i in actual for i in expected]) and all([i in expected for i in actual]) ) # Assert self.assertCountEqual(expected, actual) for (_, attrs) in graph.nodes(data=True): self.assertTrue('tested' in attrs) self.assertTrue('defense' not in attrs) self.assertTrue('dangerous' not in attrs) self.assertTrue('vulnerable' not in attrs) def test_load_call_graph_entry_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('entry' in attrs) else: self.assertTrue('entry' not in attrs) def test_load_call_graph_entry_nodes_file_granularity(self): # Arrange expected = [] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('entry' in attrs) else: self.assertTrue('entry' not in attrs) def test_load_call_graph_exit_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('exit' in attrs) else: self.assertTrue('exit' not in attrs) def test_load_call_graph_exit_nodes_file_granularity(self): # Arrange expected = [] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('exit' in attrs) else: self.assertTrue('exit' not in attrs) def test_load_call_graph_edges(self): # Arrange expected = [ ( Call('greet_b', './src/helloworld.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C) ), ( Call('recursive_b', './src/greetings.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C) ), ( Call('recursive_a', './src/greetings.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C) ), ( Call('greet_a', './src/helloworld.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C) ), ( Call('recursive_a', './src/greetings.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C) ), ( Call('recursive_b', './src/greetings.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C) ), ( Call('greet_a', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C) ), ( Call('greet', './src/greetings.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C) ), ( Call('greet_b', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C) ), ( Call('greet', './src/greetings.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHi', './src/helloworld.c', Env.C) ), ( Call('GreeterSayHi', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHiTo', './src/helloworld.c', Env.C) ), ( Call('GreeterSayHiTo', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('addInt', './src/helloworld.c', Env.C) ), ( Call('addInt', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C) ), ( Call('greet_a', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C) ), ( Call('greet_b', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ), ( Call('main', './src/helloworld.c', Env.C), Call('new_Greeter', './src/helloworld.c', Env.C) ), ( Call('new_Greeter', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C) ) ] # Act graph = self.target.load_call_graph() actual = graph.edges() # Assert self.assertCountEqual(expected, actual) for (_, _, attrs) in graph.edges(data=True): self.assertTrue('gprof' in attrs) self.assertTrue('cflow' not in attrs) self.assertTrue('call' in attrs or 'return' in attrs) def test_load_call_graph_edges_file_granularity(self): # Arrange expected = [ ( Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE) ), ( Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE) ), ( Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE) ), ( Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE) ) ] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) actual = graph.edges() # Assert self.assertCountEqual(expected, actual) for (_, _, attrs) in graph.edges(data=True): self.assertTrue('gprof' in attrs) self.assertTrue('cflow' not in attrs) self.assertTrue('call' in attrs or 'return' in attrs) def test_load_call_graph_return_edges(self): # Act graph = self.target.load_call_graph() # Assert self.assertTrue(nx.is_strongly_connected(graph)) for (u, v) in nx.get_edge_attributes(graph, 'call'): self.assertTrue('return' in graph[v][u]) def test_load_call_graph_return_edges_file_granularity(self): # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert self.assertTrue(nx.is_strongly_connected(graph)) for (u, v) in nx.get_edge_attributes(graph, 'call'): self.assertTrue('return' in graph[v][u])
def main(): args = parse_args() call_graph = None if args.javacg: loader = JavaCGLoader(args.javacg, args.apppackages) call_graph = CallGraph.from_loader(loader) else: cflow_loader = None gprof_loader = None if args.cflow: if not os.path.exists(args.cflow): raise Exception('{} not found.'.format(args.cflow)) else: cflow_loader = CflowLoader(args.cflow, reverse=args.reverse) if args.gprof: if not os.path.exists(args.gprof): raise Exception('{} not found.'.format(args.gprof)) else: if os.path.isdir(args.gprof): sources = [ os.path.join(args.gprof, filename) for filename in os.listdir(args.gprof) if os.path.isfile(os.path.join(args.gprof, filename)) ] gprof_loader = MultigprofLoader(sources, processes=args.processes) else: gprof_loader = GprofLoader(args.gprof) if cflow_loader and gprof_loader: call_graph = CallGraph.from_merge( CallGraph.from_loader(cflow_loader, granularity=args.granularity), CallGraph.from_loader(gprof_loader, granularity=args.granularity)) elif cflow_loader: call_graph = CallGraph.from_loader(cflow_loader, granularity=args.granularity) elif gprof_loader: call_graph = CallGraph.from_loader(gprof_loader, granularity=args.granularity) if args.output: (name, extension) = os.path.splitext(args.output) output_format = extension.replace('.', '') if output_format not in FORMATTERS: output_format = 'txt' formatter = FORMATTERS[output_format](call_graph) with open(args.output, 'w') as file_: if args.verbose: file_.write(formatter.write_output()) else: file_.write(formatter.write_summary()) else: formatter = FORMATTERS['txt'](call_graph) if args.verbose: sys.stdout.write(formatter.write_output()) else: sys.stdout.write(formatter.write_summary()) if args.showerrors and call_graph.load_errors: sys.stdout.write('Parse Errors\n') sys.stdout.write('============\n') for error in call_graph.load_errors: sys.stdout.write(error)
class GprofLoaderTestCase(unittest.TestCase): def setUp(self): self.target = GprofLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt'), False) def test_load_call_graph_errors(self): # Act graph = self.target.load_call_graph() # Assert self.assertEqual(0, len(self.target.errors)) def test_load_call_graph_nodes(self): # Arrange expected = [ Call('GreeterSayHiTo', './src/helloworld.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C), Call('new_Greeter', './src/helloworld.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C), Call('addInt', './src/helloworld.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHi', './src/helloworld.c', Env.C) ] # Act graph = self.target.load_call_graph() actual = graph.nodes() match = (all([i in actual for i in expected]) and all([i in expected for i in actual])) # Assert self.assertCountEqual(expected, actual) for (_, attrs) in graph.nodes(data=True): self.assertTrue('tested' in attrs) self.assertTrue('defense' not in attrs) self.assertTrue('dangerous' not in attrs) self.assertTrue('vulnerable' not in attrs) def test_load_call_graph_nodes_file_granularity(self): # Arrange expected = [ Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE) ] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) actual = graph.nodes() match = (all([i in actual for i in expected]) and all([i in expected for i in actual])) # Assert self.assertCountEqual(expected, actual) for (_, attrs) in graph.nodes(data=True): self.assertTrue('tested' in attrs) self.assertTrue('defense' not in attrs) self.assertTrue('dangerous' not in attrs) self.assertTrue('vulnerable' not in attrs) def test_load_call_graph_entry_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('entry' in attrs) else: self.assertTrue('entry' not in attrs) def test_load_call_graph_entry_nodes_file_granularity(self): # Arrange expected = [] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('entry' in attrs) else: self.assertTrue('entry' not in attrs) def test_load_call_graph_exit_nodes(self): # Arrange expected = [] # Act graph = self.target.load_call_graph() # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('exit' in attrs) else: self.assertTrue('exit' not in attrs) def test_load_call_graph_exit_nodes_file_granularity(self): # Arrange expected = [] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert for (n, attrs) in graph.nodes(data=True): if n in expected: self.assertTrue('exit' in attrs) else: self.assertTrue('exit' not in attrs) def test_load_call_graph_edges(self): # Arrange expected = [ (Call('greet_b', './src/helloworld.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C)), (Call('recursive_b', './src/greetings.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C)), (Call('recursive_a', './src/greetings.c', Env.C), Call('recursive_b', './src/greetings.c', Env.C)), (Call('greet_a', './src/helloworld.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C)), (Call('recursive_a', './src/greetings.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C)), (Call('recursive_b', './src/greetings.c', Env.C), Call('recursive_a', './src/greetings.c', Env.C)), (Call('greet_a', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C)), (Call('greet', './src/greetings.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C)), (Call('greet_b', './src/helloworld.c', Env.C), Call('greet', './src/greetings.c', Env.C)), (Call('greet', './src/greetings.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHi', './src/helloworld.c', Env.C)), (Call('GreeterSayHi', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('GreeterSayHiTo', './src/helloworld.c', Env.C)), (Call('GreeterSayHiTo', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('addInt', './src/helloworld.c', Env.C)), (Call('addInt', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('greet_a', './src/helloworld.c', Env.C)), (Call('greet_a', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('greet_b', './src/helloworld.c', Env.C)), (Call('greet_b', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)), (Call('main', './src/helloworld.c', Env.C), Call('new_Greeter', './src/helloworld.c', Env.C)), (Call('new_Greeter', './src/helloworld.c', Env.C), Call('main', './src/helloworld.c', Env.C)) ] # Act graph = self.target.load_call_graph() actual = graph.edges() # Assert self.assertCountEqual(expected, actual) for (_, _, attrs) in graph.edges(data=True): self.assertTrue('gprof' in attrs) self.assertTrue('cflow' not in attrs) self.assertTrue('call' in attrs or 'return' in attrs) def test_load_call_graph_edges_file_granularity(self): # Arrange expected = [ (Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE)), (Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE)), (Call('', './src/greetings.c', Env.C, Gran.FILE), Call('', './src/greetings.c', Env.C, Gran.FILE)), (Call('', './src/helloworld.c', Env.C, Gran.FILE), Call('', './src/helloworld.c', Env.C, Gran.FILE)) ] # Act graph = self.target.load_call_graph(granularity=Gran.FILE) actual = graph.edges() # Assert self.assertCountEqual(expected, actual) for (_, _, attrs) in graph.edges(data=True): self.assertTrue('gprof' in attrs) self.assertTrue('cflow' not in attrs) self.assertTrue('call' in attrs or 'return' in attrs) def test_load_call_graph_return_edges(self): # Act graph = self.target.load_call_graph() # Assert self.assertTrue(nx.is_strongly_connected(graph)) for (u, v) in nx.get_edge_attributes(graph, 'call'): self.assertTrue('return' in graph[v][u]) def test_load_call_graph_return_edges_file_granularity(self): # Act graph = self.target.load_call_graph(granularity=Gran.FILE) # Assert self.assertTrue(nx.is_strongly_connected(graph)) for (u, v) in nx.get_edge_attributes(graph, 'call'): self.assertTrue('return' in graph[v][u])
def stat(**options): cflow_path = options.get('cflow_path', None) gprof_path = options.get('gprof_path', None) num_processes = options.get('num_processes') output = options.get('output', False) threshold = options.get('threshold', None) subject = options.get('subject', None) revision = options.get('revision', None) if subject not in settings.ENABLED_SUBJECTS: raise CommandError('Subject {0} is not enabled'.format(subject)) cflow_loader = None gprof_loader = None cflow_call_graph = None gprof_call_graph = None begin = datetime.datetime.now() if cflow_path: fragmentize = False if not gprof_path: fragmentize = True print('Loading cflow call graph') cflow_loader = CflowLoader(cflow_path, reverse=True) cflow_call_graph = CallGraph.from_loader(cflow_loader, fragmentize) if gprof_path: fragmentize = False if not cflow_path: fragmentize = True print('Loading gprof call graph') if os.path.isdir(gprof_path): sources = [ os.path.join(gprof_path, file_name) for file_name in os.listdir(gprof_path) if 'txt' in file_name ] os.environ['DEBUG'] = '1' gprof_loader = MultigprofLoader(sources, processes=num_processes) gprof_call_graph = CallGraph.from_loader(gprof_loader, fragmentize) else: gprof_loader = GprofLoader(gprof_path, reverse=False) gprof_call_graph = CallGraph.from_loader(gprof_loader, fragmentize) end = datetime.datetime.now() call_graph = None if cflow_call_graph and gprof_call_graph: if 'DEBUG' in os.environ: print() print('Merging cflow and gprof call graphs') call_graph = CallGraph.from_merge(cflow_call_graph, gprof_call_graph, fragmentize=True) elif cflow_call_graph: call_graph = cflow_call_graph elif gprof_call_graph: call_graph = gprof_call_graph if not call_graph: print('Nothing to stat. Exiting.') sys.exit(0) print('Load completed in {0:.2f} seconds'.format( (end - begin).total_seconds())) print('#' * 50) print(' Call Graph Statistics') print('#' * 50) print(' Nodes {0}'.format(len(call_graph.nodes))) print(' Edges {0}'.format(len(call_graph.edges))) print(' Entry Points {0}'.format(len(call_graph.entry_points))) print(' Exit Points {0}'.format(len(call_graph.exit_points))) print(' Dangerous {0}'.format( len(nx.get_node_attributes(call_graph.call_graph, 'dangerous')))) print(' Monolithicity {0:4f}'.format(call_graph.monolithicity)) print(' Fragments {0}'.format(call_graph.num_fragments)) print('#' * 50) if output: generate(subject, revision, call_graph, threshold, num_processes)
def setUp(self): self.target = CallGraph.from_loader(GprofLoader( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'helloworld/gprof.callgraph.txt'), True), granularity=Granularity.FILE)