1 #!/usr/bin/perl 2 3 use strict; 4 5 sub usage() 6 { 7 print "Usage: unlocked_paths.pl <call tree file> <lock> <function>\n"; 8 print "Prints a list of paths to <function> which don't take the <lock>.\n"; 9 print "Generate the call tree file by running smatch with --call-tree.\n"; 10 exit(1); 11 } 12 13 my %f_map; 14 15 sub add_to_map($) 16 { 17 my $callee = shift; 18 19 if (!defined($f_map{$callee})) { 20 $f_map{$callee} = {visited => 0, called_by => {}}; 21 } 22 } 23 24 sub add_called_by($$) 25 { 26 my $caller = shift; 27 my $callee = shift; 28 my $tmp; 29 30 %{$f_map{$callee}->{called_by}}->{$caller} = 1; 31 } 32 33 sub load_all($$) 34 { 35 my $file = shift; 36 my $lock = shift; 37 38 open(FILE, "<$file"); 39 while (<FILE>) { 40 if (/.*?:\d+ (.*?)\(\) info: func_call \((.*)\) (.*)/) { 41 my $caller = quotemeta $1; 42 my $locks = quotemeta $2; 43 my $callee = quotemeta $3; 44 45 add_to_map($callee); 46 if (!($locks =~ /$lock/)) { 47 add_called_by($caller, $callee); 48 } 49 } 50 } 51 } 52 53 my @fstack; 54 sub print_fstack() 55 { 56 foreach my $f (reverse @fstack) { 57 printf "$f "; 58 } 59 printf "\n"; 60 } 61 62 sub print_unlocked_paths($) 63 { 64 my $function = shift; 65 66 if (! defined %{$f_map{$function}}->{called_by}) { 67 push @fstack, $function; 68 print_fstack(); 69 pop @fstack; 70 return; 71 } 72 73 push @fstack, $function; 74 75 if (!%{$f_map{$function}}->{visited}) { 76 %{$f_map{$function}}->{visited} = 1; 77 foreach my $caller (keys %{%{$f_map{$function}}->{called_by}}){ 78 print_unlocked_paths($caller); 79 } 80 %{$f_map{$function}}->{visited} = 0; 81 82 } 83 84 pop @fstack; 85 } 86 87 my $file = shift; 88 my $lock = shift; 89 my $target = shift; 90 91 if (!$file || !$lock || !$target) { 92 usage(); 93 } 94 if (! -e $file) { 95 printf("Error: $file does not exist.\n"); 96 exit(1); 97 } 98 99 load_all($file, $lock); 100 print_unlocked_paths($target);