source: branches/properties/SOURCE_TOOLS/deadcode.pl

Last change on this file was 18914, checked in by westram, 3 years ago
  • fix error handling for piped commands in perl
    • when forking piped commands
      • use error message ($!) instead of exitcode ($?).
      • use message 'failed to fork'.
    • when closing piped commands
      • show IPC errors and exitcode of command.
  • Property svn:executable set to *
File size: 6.6 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6my @symbol_priority = (
7                       '::', # class members
8                       '^TEST_', # ARB unit tests
9                       '^publishTEST_', # ARB unit tests (published)
10                       '^GBP_', # perl interface functions
11                       '^(create|destroy|copy|save|load)_(AN|PT|dll)_', # AISC generated functions
12                       '^main$',
13                      );
14
15my $reg_file_exclude = qr/\/(GDE|EISPACK|READSEQ|PERL2ARB)\//;
16
17sub findObjects(\@) {
18  my ($libs_r) = @_;
19
20  my $cmd = 'find . -name "*.o"';
21  open(FOUND,$cmd.'|') || die "failed to fork '$cmd' (Reason: $!)";
22  foreach (<FOUND>) {
23    chomp $_;
24    if (not $_ =~ $reg_file_exclude) {
25      push @$libs_r, $_;
26    }
27  }
28  close(FOUND) || die "failed to execute '$cmd' (Reason: $! exitcode=$?)";
29}
30
31sub is_weak($) {
32  my ($type) = @_;
33  return ($type =~ /^[vVwW]$/o);
34}
35
36# ------------------------------ store symbols
37
38my %def_loc = (); # key = symbol, value=ref to array [ file, line, type ]
39my %dupdef_loc = (); # key = symbol, value=ref to array of refs to array [ file, line, type ]
40
41my %referenced = (); # key=symbol, value=1 -> has been referenced
42
43sub set_definition($$$$) {
44  my ($sym,$file,$line,$type) = @_;
45  my @array = ($file,$line,$type);
46  $def_loc{$sym} = \@array;
47}
48
49sub add_dup_definition($$$$) {
50  my ($sym,$file,$line,$type) = @_;
51
52  my @array = ($file,$line,$type);
53  my $dups_r = $dupdef_loc{$sym};
54
55  if (not defined $dups_r) {
56    my @dups = ( \@array );
57    $dupdef_loc{$sym} = \@dups;
58  }
59  else {
60    my $add = 1;
61  LOOKUP: foreach my $duploc_r (@$dups_r) {
62      my ($dfile,$dline,$dtype) = @$duploc_r;
63      if (($dfile eq $file) and ($dline eq $line)) { # already have that location
64        $add = 0;
65        last LOOKUP;
66      }
67    }
68    if ($add==1) {
69      push @$dups_r, \@array;
70    }
71  }
72}
73
74sub definesSymbol($$$$$) {
75  my ($obj,$file,$line,$sym,$type) = @_;
76
77  my $loc_r = $def_loc{$sym};
78  if (not defined $loc_r) { set_definition($sym,$file,$line,$type); }
79  else {
80    my ($pfile,$pline,$ptype) = @$loc_r;
81    if (($file ne $pfile) and ($line != $pline)) { # locations differ
82      if (is_weak($ptype) and not is_weak($type)) {
83        set_definition($sym,$file,$line,$type);
84        add_dup_definition($sym,$pfile,$pline,$ptype);
85      }
86      else { add_dup_definition($sym,$file,$line,$type); }
87    }
88  }
89}
90
91sub referencesSymbol($$$) {
92  my ($obj,$sym,$type) = @_;
93  $referenced{$sym} = $obj;
94}
95
96# ------------------------------ analyse
97
98sub list_unreferenced_symbols() {
99  print "Checking unreferenced symbols:\n";
100
101  my @undefs = ();
102  foreach my $sym (keys %def_loc) {
103    my $ref_r = $referenced{$sym};
104    if (not defined $ref_r) {
105      my $def_r = $def_loc{$sym};
106      my ($file,$line,$type) = @$def_r;
107      if (not is_weak($type) and # ignore weak unrefs
108          not $file =~ /^\/usr\/include\//o # ignore unrefs if /usr/include
109          ) { 
110        push @undefs, $sym;
111      }
112    }
113  }
114
115  @undefs = sort {
116    my $la_r = $def_loc{$a};
117    my $lb_r = $def_loc{$b};
118    my $cmp = $$la_r[0] cmp $$lb_r[0];
119    if ($cmp==0) { $cmp = $$la_r[1] <=> $$lb_r[1]; }
120    $cmp;
121  } @undefs;
122
123  my %importance = map { $_ => 1; } @undefs; # key=sym, value=importance (lower = more important)
124
125  my $regs = scalar(@symbol_priority);
126  for (my $r = 0; $r<$regs; $r++) {
127    my $expr = $symbol_priority[$r];
128    my $imp = $r+2;
129    my $reg = qr/$expr/;
130    foreach my $sym (@undefs) {
131      if ($sym =~ $reg) {
132        $importance{$sym} = $imp;
133      }
134    }
135  }
136  my $max_imp = $regs+1;
137  for (my $i=1; $i<=$max_imp; $i++) {
138    print "Symbols for importance==$i:\n";
139    foreach my $sym (@undefs) {
140      if ($importance{$sym} == $i) {
141        my $def_r = $def_loc{$sym};
142        my ($file,$line,$type) = @$def_r;
143        print "$file:$line: unreferenced '$sym' [$type]\n";
144      }
145    }
146  }
147}
148
149sub list_duplicate_defines() {
150  print "Checking duplicate definitions :\n";
151  foreach my $sym (keys %dupdef_loc) {
152    my $main_def_r = $def_loc{$sym};
153    my ($file,$line,$type) = @$main_def_r;
154    if (not is_weak($type)) { # dont warn about weak symbols
155      my $dup_def_r = $dupdef_loc{$sym};
156      my $onlyWeakDups = 1;
157      foreach my $dup_r (@$dup_def_r) {
158        my ($dfile,$dline,$dtype) = @$dup_r;
159        if (not is_weak($dtype)) {
160          if ($onlyWeakDups==1) { # first non-weak dup -> start
161            print "$file:$line: Multiple definition of '$sym' [$type]\n";
162            $onlyWeakDups = 0;
163          }
164          print "$dfile:$dline: duplicate definition [$dtype]\n";
165        }
166      }
167    }
168  }
169}
170
171# ------------------------------ parse
172
173my $reg_def = qr/^(.*)\s([BDRTVW])\s([0-9a-f]+)\s([0-9a-f]+)\s+([^\s]+):([0-9]+)$/;
174my $reg_def_noloc = qr/^(.*)\s([BDRTVW])\s([0-9a-f]+)\s([0-9a-f]+)$/;
175my $reg_def_noloc_oneadd = qr/^(.*)\s([AT])\s([0-9a-f]+)\s+$/;
176
177my $reg_refer = qr/^(.*)\s([Uw])\s+([^\s]+):([0-9]+)$/;
178my $reg_refer_noloc = qr/^(.*)\s([Uw])\s+$/;
179
180sub dump_unhandled_line($$) {
181  my ($tag,$line) = @_;
182  if (0) {
183    print "unhandled [$tag] : $line\n";
184  }
185}
186
187sub scanObj($) {
188  my ($obj) = @_;
189
190  my $cmd = 'nm -l -P -p -g '.$obj.' 2>&1 | c++filt ';
191  open(SYMBOLS,$cmd.'|') || die "failed to fork '$cmd' (Reason: $!)";
192  my $line;
193  while (defined($line=<SYMBOLS>)) {
194    chomp($line);
195
196    if ($line =~ $reg_def) {
197      my ($sym,$type,$add1,$add2,$file,$line) = ($1,$2,$3,$4,$5,$6);
198      definesSymbol($obj,$file,$line,$sym,$type);
199    }
200    elsif ($line =~ $reg_def_noloc) { dump_unhandled_line("noloc1", $line); }
201    elsif ($line =~ $reg_def_noloc_oneadd) { dump_unhandled_line("noloc2", $line); }
202    elsif ($line =~ $reg_refer) {
203      my ($sym,$type,$file,$line) = ($1,$2,$3,$4);
204      referencesSymbol($obj,$sym,$type);
205    }
206    elsif ($line =~ $reg_refer_noloc) {
207      my ($sym,$type) = ($1,$2);
208      referencesSymbol($obj,$sym,$type);
209    }
210    else {
211      die "can't parse line '$line'\n";
212    }
213  }
214  close(SYMBOLS) || die "failed to execute '$cmd' (Reason: $! exitcode=$?)";
215}
216
217sub main() {
218  print "DeadCode detector\n";
219  print "- detects useless external linkage, that could go static\n";
220  print "  (then the compiler will warn if code/data is unused)\n";
221  print "- needs compilation with DEBUG information\n";
222  print "- also lists\n";
223  print "  - useless stuff like class-members, xsub-syms\n";
224  print "  - duplicated global symbols\n";
225
226  my @objs;
227  findObjects(@objs);
228  print 'Examining '.scalar(@objs)." objs\n";
229
230  foreach my $obj (@objs) {
231    scanObj($obj);
232  }
233
234  print "Summary :\n";
235  print " - found ".scalar(keys %def_loc)." defined symbols\n";
236  print " - found ".scalar(keys %referenced)." referenced symbols\n";
237
238  list_unreferenced_symbols();
239  list_duplicate_defines();
240}
241main();
Note: See TracBrowser for help on using the repository browser.