1#!/usr/bin/perl
2
3# This script is supposed to help use the param_mapper output.
4# Give it a function and parameter and it lists the functions
5# and parameters which are basically equivalent.
6
7use strict;
8
9sub usage()
10{
11    print("call_tree.pl <smatch output file>\n");
12    print("call_tree.pl finds paths between two functions\n");
13    exit(1);
14}
15
16my %param_map;
17
18my $UNKNOWN  = 1;
19my $NOTFOUND = 2;
20my $FOUND    = 3;
21
22my $path;
23
24sub print_path()
25{
26    my $i = 0;
27
28    foreach my $func (@{$path}) {
29	if ($i++) {
30	    print(", ");
31	}
32	print("$func");
33    }
34    print("\n");
35    print("\n");
36}
37
38sub recurse($$)
39{
40    my $link = shift;
41    my $target = shift;
42    my $found = 0;
43
44    if ($link =~ /$target/) {
45	print_path();
46	return 1;
47    }
48    if (%{$param_map{$link}}->{found} == $NOTFOUND) {
49	return 0;
50    }
51
52    %{$param_map{$link}}->{found} = $NOTFOUND;
53
54    foreach my $l (@{%{$param_map{$link}}->{links}}){
55	push(@{$path}, $l);
56	$found = recurse($l, $target);
57	if (!$found) {
58	    pop(@{$path});
59	} else {
60	    last;
61	}
62    }
63
64    return $found;
65}
66
67sub search($$)
68{
69    my $start_func = shift;
70    my $end_func = shift;
71
72    foreach my $link (@{%{$param_map{$start_func}}->{links}}){
73	%{$param_map{$start_func}}->{found} = $NOTFOUND;
74	foreach my $l (@{%{$param_map{$start_func}}->{links}}){
75	    %{$param_map{$l}}->{found} = $NOTFOUND;
76	}
77	$path = [$start_func, $link];
78	%{$param_map{$link}}->{found} = $UNKNOWN;
79	recurse($link, $end_func);
80    }
81}
82
83sub add_link($$)
84{
85    my $one = shift;
86    my $two = shift;
87
88    if (!defined($param_map{$one})) {
89	$param_map{$one} = {found => $UNKNOWN, links => []};
90    }
91    push @{$param_map{$one}->{links}}, $two;
92}
93
94sub load_all($)
95{
96    my $file = shift;
97
98    open(FILE, "<$file");
99    while (<FILE>) {
100	if (/.*?:\d+ (.*?)\(\) info: func_call (.*)/) {
101	    add_link("$1", "$2");
102	}
103    }
104}
105
106sub set_all_unknown()
107{
108    my $i = 0;
109
110    foreach my $func (keys %param_map){
111	%{$param_map{$func}}->{found} = $UNKNOWN;
112    }
113}
114
115my $file = shift();
116if (!$file) {
117    usage();
118}
119
120if (! -e $file) {
121    printf("Error:  $file does not exist.\n");
122    exit(1);
123}
124
125print("Loading functions...\n");
126load_all($file);
127
128while (1) {
129    my $start_func;
130    my $end_func;
131
132    print("Enter the start function:  ");
133    $start_func = <STDIN>;
134    $start_func =~ s/^\s+|\s+$//g;
135    print("Enter the target function:  ");
136    $end_func = <STDIN>;
137    $end_func =~ s/^\s+|\s+$//g;
138
139
140    print("$start_func to $end_func\n");
141    if ($start_func =~ /./ && $end_func =~ /./) {
142	search($start_func, $end_func);
143    }
144
145    set_all_unknown();
146}
147