source: tags/svn.1.5.4/SOURCE_TOOLS/valgrind2grep

Last change on this file was 8038, checked in by westram, 14 years ago

merge from dev [7963] [7964] [7965]

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