Home | History | Annotate | Download | only in tests
      1 #!/usr/bin/env perl
      2 
      3 #---------------------------------------------------------------------
      4 # Quick and dirty program to filter helgrind's XML output.
      5 # 
      6 # The script works line-by-line and is generally unaware of XML structure
      7 # and does not bother with issues of well-formedness.
      8 #
      9 # Consists of two parts
     10 # (1) Global match and replace (see PATTERNS below)
     11 # (2) Removal of stack frames
     12 #     Stack frames whose associated file name does not match any name in
     13 #     TOOL_FILES or in the list of files given on the command line
     14 #     will be discarded. For a sequence of one or more discarded frames
     15 #     a line   <frame>...</frame> will be inserted.
     16 #
     17 #---------------------------------------------------------------------
     18 
     19 use warnings;
     20 use strict;
     21 
     22 #---------------------------------------------------------------------
     23 # A list of files specific to the tool at hand. Line numbers in
     24 # these files will be removed from stack frames matching these files.
     25 #---------------------------------------------------------------------
     26 my @tool_files = ( "hg_intercepts.c", "vg_replace_malloc.c" );
     27 
     28 # List of patterns and replacement strings. 
     29 # Each pattern must identify a substring which will be replaced.
     30 my %patterns = (
     31     "<pid>(.*)</pid>"       => "...",
     32     "<ppid>(.*)</ppid>"     => "...",
     33     "<time>(.*)</time>"     => "...",
     34     "<obj>(.*)</obj>"       => "...",
     35     "<dir>(.*)</dir>"       => "...",
     36     "<exe>(.*)</exe>"       => "...",
     37     "<tid>(.*)</tid>"       => "...",
     38     "<unique>(.*)</unique>" => "...",
     39     "thread #([0-9]+)"      => "x",
     40     "0x([0-9a-zA-Z]+)"      => "........",
     41     "Using Valgrind-([^\\s]*)"    => "X.Y.X",
     42     "Copyright \\(C\\) ([0-9]{4}-[0-9]{4}).*" => "XXXX-YYYY",
     43     '<fn>pthread_.*(@\*)</fn>'  => ""
     44 );
     45 
     46 # List of XML sections to be ignored.
     47 my %ignore_sections = (
     48     "<errorcounts>" => "</errorcounts>",
     49     "<suppcounts>"  => "</suppcounts>",
     50     "pthread_create_WRK</fn>" => "<obj>"
     51 );
     52 
     53 # List of XML sections to be quietly ignored.
     54 my %quiet_ignore_sections = (
     55     "pthread_create_WRK</fn>" => "<obj>"
     56 );
     57 
     58 
     59 # If FILE matches any of the FILES return 1
     60 sub file_matches ($$) {
     61     my ($file, $files) = @_;
     62     my ($string, $qstring);
     63 
     64     foreach $string (@$files) {
     65         $qstring = quotemeta($string);
     66         return 1 if ($file =~ /$qstring/);
     67     }
     68 
     69     return 0;
     70 }
     71 
     72 
     73 my $frame_buf = "";
     74 my ($file, $lineno, $in_frame, $keep_frame, $num_discarded, $ignore_line, $quiet_ignore_line);
     75 
     76 $in_frame = $keep_frame = $num_discarded = $ignore_line = $quiet_ignore_line = 0;
     77 
     78 line: 
     79 while (<STDIN>) {
     80     my $line = $_;
     81     chomp($line);
     82 
     83 # Check whether we're ignoring this piece of XML..
     84     if ($ignore_line) {
     85         foreach my $tag (keys %ignore_sections) {
     86             if ($line =~ $ignore_sections{$tag}) {
     87                 if ($quiet_ignore_line == 0) {
     88                     print "$tag...$ignore_sections{$tag}\n";
     89                 }
     90                 $ignore_line = 0;
     91                 $quiet_ignore_line = 0;
     92                 next line;
     93             }
     94         }
     95     } else {
     96         foreach my $tag (keys %ignore_sections) {
     97             if ($line =~ $tag) {
     98                 $ignore_line = 1;
     99             }
    100         }
    101         # Determine if this section is also in the quiet list.
    102         foreach my $tag (keys %quiet_ignore_sections) {
    103             if ($line =~ $tag) {
    104                 $quiet_ignore_line = 1;
    105             }
    106         }
    107     }
    108 
    109     next if ($ignore_line);
    110 
    111 # OK. This line is not to be ignored.
    112 
    113 # Massage line by applying PATTERNS.
    114     foreach my $key (keys %patterns) {
    115         if ($line =~ $key) {
    116            my $matched = quotemeta($1);
    117            $line =~ s/$matched/$patterns{$key}/g;
    118         }
    119     }
    120 
    121 # Handle frames
    122     if ($in_frame) {
    123         if ($line =~ /<\/frame>/) {
    124             $frame_buf .= "$line\n";
    125 # The end of a frame
    126             if ($keep_frame) {
    127 # First: If there were any preceding frames that were discarded
    128 #        print <frame>...</frame>
    129                 if ($num_discarded) {
    130                     print "    <frame>...</frame>\n";
    131                     $num_discarded = 0;
    132                 }
    133 # Secondly: Write out the frame itself
    134                 print "$frame_buf";
    135             } else {
    136 # We don't want to write this frame
    137                 ++$num_discarded;
    138             }
    139             $in_frame = $keep_frame = 0;
    140             $file = "";
    141         } elsif ($line =~ /<file>(.*)<\/file>/) {
    142             $frame_buf .= "$line\n";
    143             $file = $1;
    144             if (file_matches($file, \@tool_files) ||
    145                 file_matches($file, \@ARGV)) {
    146                 $keep_frame = 1;
    147             }
    148         } elsif ($line =~ /<line>(.*)<\/line>/) {
    149 # This code assumes that <file> always precedes <line>
    150             $lineno = $1;
    151             if (file_matches($file, \@tool_files)) {
    152                 $line =~ s/$1/.../;
    153             }
    154             $frame_buf .= "$line\n";
    155         } else {
    156             $frame_buf .= "$line\n";
    157         }
    158     } else {
    159 # not within frame
    160         if ($line =~ /<\/stack>/) {
    161             print "    <frame>...</frame>\n" if ($num_discarded);
    162             $num_discarded = 0;
    163         }
    164         if ($line =~ /<frame>/)  {
    165             $in_frame = 1;
    166             $frame_buf = "$line\n";
    167         } else {
    168             print "$line\n";
    169         }
    170     }
    171 } 
    172 
    173 exit 0;
    174