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