source: branches/port5/SOURCE_TOOLS/valgrind2grep

Last change on this file was 6058, checked in by westram, 15 years ago
  • suppress known mem-leaks in system libs
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1#!/usr/bin/perl
2
3use warnings;
4use strict;
5use IO::Handle;
6
7# -------------------------------------------------------------------- customize here
8
9# top source directory
10my $topdir = "$ENV{ARBHOME}";
11
12# list containing paths of all source files (generated by arb_valgrind)
13my $sourcelist = "$topdir/SOURCE_TOOLS/valgrind2grep.lst";
14
15# prefix to write before hidden caller-lines
16# (-> emacs will not jump to them automatically, you have to remove the prefix first)
17my $unmark_callers  = "(hide) ";
18
19# prefix to write before filtered lines
20my $unmark_filtered = "(filt) ";
21
22# prefix to write before other non-error lines
23my $unmark_rest     = "(note) ";
24
25sub check_ignore($\$$) {
26  my ($text,$ignore_r,$reason) = @_;
27  if (not defined $$ignore_r) {
28    # if you encounter errors/warnings in foreign libraries you wont be able to fix them.
29    # To ignore them add a search expression here.
30    # Please add current date as well, to make it easier to find outdated expressions.
31
32    if ($reason =~ 'loss record') { # memory leaks
33      # Xtoolkit leaks:
34      if ($text =~ /\b(XtAppMainLoop)\b.*libXt/) { $$ignore_r = $&; return; } # 15/06/2009
35    }
36    else { # illegal memory access
37      # X11 bugs:
38      if ($text =~ /\b(_X11TransWrite)\b.*libX11/) { $$ignore_r = $&; return; } # 24/11/2005
39      if ($text =~ /\b(_XSend)\b.*libX11/) { $$ignore_r = $&; return; } # 16/05/2009
40      # Xtoolkit bugs:
41      if ($text =~ /\b(_XtGet(Sub)?[rR]esources)\b.*libXt/) { $$ignore_r = $&; return; } # 24/11/2005
42      if ($text =~ /\b(XtOpenApplication)\b.*libXt/) { $$ignore_r = $&; return; } # 13/06/2009
43      # motif bugs:
44      if ($text =~ /\b(XmRenderTableCopy)\b.*libXm/) { $$ignore_r = $&; return; } # 09/02/2009
45      if ($text =~ /\b(XmRenderTableFree)\b.*libXm/) { $$ignore_r = $&; return; } # 09/02/2009
46      if ($text =~ /\b(XmIsMotifWMRunning)\b.*libXm/) { $$ignore_r = $&; return; } # 13/06/2009
47    }
48  }
49}
50
51my $debug = 0;
52
53# --------------------------------------------------------------- customize till here
54
55# get args:
56
57my $args = scalar(@ARGV);
58
59if ($args<2 or $args>3) { die "Usage: valgrind2grep <callers> <filter> [--suppress-common]\n"; }
60my $callers = $ARGV[0];
61my $filter  = $ARGV[1];
62
63my $suppress_common = 0;
64if ($args==3) {
65  my $a = $ARGV[2];
66  if ($a eq '--suppress-common') { $suppress_common=1; }
67  else { die "Unknown argument '$a'"; }
68}
69
70# use unbuffered I/O (otherwise pipe waits for valgrind to terminate???)
71
72my $in = new IO::Handle;
73$in->fdopen(fileno(STDIN),"r") || die "can't open STDIN";
74
75my $out = new IO::Handle;
76$out->fdopen(fileno(STDOUT),"w") || die "can't open STDOUT";
77
78# read list of source files:
79
80open(SOURCELIST,"<$sourcelist") || die "can't open $sourcelist";
81
82my %fileIndex = ();
83
84sub addFileIndex($$) {
85  my ($key,$val) = @_;
86  if (not exists $fileIndex{$key}) {
87    my @array = ();
88    $fileIndex{$key} = \@array;
89  }
90  my $array_r = $fileIndex{$key};
91  push @$array_r, $val;
92}
93
94foreach (<SOURCELIST>) {
95  chomp;
96  addFileIndex($_,$_);
97  # $fileIndex{$_} = $_;
98  if (/\/([^\/]+)\/([^\/]+)$/) {
99    my $last_dir = $1;
100    my $fname    = $2;
101
102    addFileIndex($fname,$_);
103    addFileIndex($last_dir.'/'.$fname,$_);
104    # $fileIndex{$fname} = $_;
105    # $fileIndex{$last_dir.'/'.$fname} = $_;
106  }
107  elsif (/\/([^\/]+)$/) {
108    my $fname = $1;
109    addFileIndex($fname,$_);
110    # $fileIndex{$fname} = $_;
111  }
112  else {
113    die "invalid entry in $sourcelist ('$_')"
114  }
115}
116
117close(SOURCELIST);
118
119sub makeTargetAbsolute($$) {
120  my ($abslink,$reltarget) = @_;
121  if ($abslink =~ /\/[^\/]+$/o) {
122    my $absdir = $`;
123    while ($reltarget =~ /^..\//o) {
124      $reltarget = $';
125      if ($absdir =~ /\/[^\/]+$/o) {
126        $absdir = $`;
127      }
128      else {
129        die "Can't detect parent dir of '$absdir'";
130      }
131    }
132    # print "absdir='$absdir' reltarget='$reltarget'\n";
133    return $absdir.'/'.$reltarget;
134  }
135  else {
136    die "Can't detect parent dir of '$abslink'";
137  }
138}
139
140# make entries unique
141foreach (keys %fileIndex) {
142  my $array_r = $fileIndex{$_};
143  my %unique = map { $_ => 1; } @$array_r;
144
145  my $changed = 1;
146  while ($changed==1) {
147    $changed = 0;
148    my @del = ();
149    my @add = ();
150    foreach (keys %unique) {
151      my $target = undef;
152      eval { $target = readlink($_); };
153      if ($@) {                 # a link with invalid target?
154        push @del, $_;
155        $out->print("Remove invalid link '$_' (Reason: $!)\n");
156      }
157      elsif (defined $target) { # a link with valid target
158        $target = makeTargetAbsolute($_,$target);
159        push @del, $_;
160        push @add, $target;
161        # $out->print("Replace link '$_'\n   by target '$target'\n");
162        # $out->print("Target '$target' exists:".(-e $target ? 'yes' : 'no')."\n");
163      }
164      # else not a link
165    }
166    if (scalar(@del)) { foreach (@del) { delete $unique{$_}; } $changed=1; }
167    if (scalar(@add)) { foreach (@add) { $unique{$_} = 1; } $changed=1; }
168  }
169  @$array_r = keys %unique;
170}
171
172
173$out->print("Settings: Showing $callers caller(s).\n");
174$out->print("          Filtering with '$filter'.\n");
175
176sub avoid_location($) {         # invalidate everything emacs could missinterpret as error-location (i.e. '(file:lineno)')
177  $_ = shift;
178  s/([(].*)(:)(.*[)])/$1_$2_$3/ig;
179  $_;
180}
181
182# variables:
183
184my $i;
185my $called_from      = "called from";
186my $reason           = 'no reason yet';
187my $caller_count     = 0;       # counts callers
188my $filtered         = 0;       # filter current error
189my $ignore           = undef;
190my $last_ignore      = '';
191my $ignore_curr_line = 0;
192
193# the filter loop:
194
195while (not $in->eof) {
196  # read one line:
197  $_ = $in->getline;
198
199  # convert error messages to grep format:
200  if (/^([=\-0-9]+[ ]+)(.*)$/) {
201    my $prefix  = $1;
202    my $content = $2;
203
204    if ($content =~ /^([ab][ty].*)([(][^()]+[)])$/) { # looks like an valgrind error
205      $content = $1;
206      my $location = $2;
207
208      if ($location =~ /[(](.*):(.*)[)]/) { # seems to have a valid '(file:line)' location at eol
209        my ($file,$line) = ($1,$2);
210        if ($filtered == 1) {
211          $_ = $unmark_filtered.' '.&avoid_location($_);
212        }
213        else {
214          my $array_r = $fileIndex{$file};
215          if (defined $array_r) {
216            my @lines = ();
217            if (scalar(@$array_r)>1) {
218              push @lines, $unmark_rest."Multiple occurrances of '$file' - not sure which location is the correct one\n";
219            }
220
221            if ($reason eq $called_from) { # its a caller
222              $caller_count++;
223            }
224            else {
225              $caller_count = 0;
226            }
227
228            foreach my $replace (@$array_r) {
229              if (not -f $replace) {
230                $_ = "$sourcelist:1: might be outdated ($replace does not exist)\n";
231              }
232              else {
233                $_ = "$replace:$line: $reason ($content)\n";
234                if ($caller_count > $callers) {
235                  $_ = $unmark_callers.$_;
236                }             # hide this caller
237              }
238              push @lines, $_;
239            }
240
241            $reason = $called_from;
242            $_ = join '', @lines;
243          }
244          else {                # location in unavailable file (i.e. in library)
245            $_ = $unmark_rest.$prefix.$reason." $content (in unavailable file $file line $line)\n";
246          }
247        }
248      }
249      else {                    # valgrind error w/o location
250        $_=$unmark_rest.' '.$_;
251        if ($suppress_common==1) { check_ignore($_, $ignore, $reason); }
252      }
253    }
254    else {                      # no location found
255      if ($content =~ /^TRANSLATE: / or
256          $content =~ /^Reading syms from/ or
257          $content =~ /object doesn.t have a/) {
258        $ignore_curr_line = 1;
259      }
260      elsif ($content =~ /^[ ]*$/) {
261        $ignore = undef;
262        $_      = '(    ) '.$_;
263      }
264      else {
265        $reason = $content;
266        $_='(    ) '.$_;
267
268        # should that reason be filtered ?
269        if ($reason =~ /alloc\'d/) { # an allocator message (applies to last message) -> so never filter
270          $reason = "ORIGIN: $reason";
271          # keep $ignore like before
272        }
273        else {
274          if ($reason =~ /$filter/i) { $filtered = 0; }
275          else { $filtered = 1; }
276
277          if ($filtered == 1) { $ignore = undef; }
278        }
279      }
280    }
281  }
282
283  # print out line
284  if ($ignore_curr_line==0) { 
285    if (not defined $ignore) {
286      $out->print($_);
287      $out->flush;
288      $last_ignore = '';
289    }
290    else {
291      if ($ignore ne $last_ignore) {
292        s/^\(note\)[ ]*//;
293        $out->print("(igno) '$ignore' ".$_);
294        $out->print("(skip) further messages suppressed\n");
295        $out->flush;
296        $last_ignore = $ignore;
297      }
298      else {
299        if ($debug==1) {
300          $out->print("(comm) ".$_);
301          $out->flush;
302        }
303      }
304    }
305  }
306  else {
307    if ($debug==1) {
308      $out->print("(SUPP) ".$_);
309      $out->flush();
310    }
311    $ignore_curr_line = 0;
312  }
313}
314
315$in->close;
316$out->close;
317
Note: See TracBrowser for help on using the repository browser.