On Tue, 2002-06-04 at 14:49, Randy.Dunlap wrote:
> On Tue, 4 Jun 2002, Marc Britten wrote:

> | helps keep the noise level down when scanning large logs.
> |
> | I'll post it if anyone is interested.
> 
> Yes, please do.

logparse.pl -? to get a rundown, you still need to pipe it through less
or more or something
#!/usr/bin/perl -w

use strict;
use Getopt::Std;

# Global variable for line info to avoid passing it all around
my $LineNo;		# Line number in log file
my $LineTime;		# Time elapsed when this line was written
my $Line;		# Rest of line
my $PeekFlag = 0;	# Lookahead flag (ugh!)
my $UrbTime = 0;	# Time elapsed when this URB was sent
my $LastUrbTime = 0;	# Time elapsed when previous URB was sent
my $FreeStyle = 0;	# Allow lines with no obvious timestamp or line tag

my $LastVendor= '';	# Last vendor request

my %UrbTypeMap = (
   'URB_FUNCTION_CONTROL_TRANSFER'		=>	'Control Transfer',
   'URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE'	=>	'Get Descriptor',
   'URB_FUNCTION_SELECT_CONFIGURATION'		=>	'Select Config',
   'URB_FUNCTION_VENDOR_INTERFACE'		=>	'Vendor I/F',
);

#############################################################################
# Argument processing

my %Opt;
getopts( 'qstv', \%Opt )
    or Usage();
my $Quiet = $Opt{'q'};		# Very quiet output
my $Verbose = $Opt{'v'};	# Verbose output
my $ShowSetup = $Opt{'s'};	# Show setup packet data too
my $ShowTime = $Opt{'t'};	# Show time information


#############################################################################
# Main loop

while( PeekLine() ) {
    if( $Line =~ /^>>>/ ) {
	ParseOutgoing();
    }
    elsif( $Line =~ /^<<</ ) {
	ParseIncoming();
    }
    else {
	print "State error: Unexpected line '$Line' at $LineNo !\n";
	ReadLine();
    }
}
print "Done.\n";
exit 0;
#############################################################################

sub ParseOutgoing {
    my $UrbDir = '->';
    my ( $UrbId, $UrbType );

    # Read and parse the URB direction & number header
    ReadLine() or die "Read error\n";
    if( $Line =~ />> +URB (\d+) going down/ ) {
	$UrbId = $1;			# Save the ID number
	# Read and parse the URB type
	ReadLine() or die "Read error\n";
	if( $Line =~ /^-- ?(\S+):/ ) {
	    $UrbType = $1;
	}
	else {
	    die "State error: Unexpected line '$Line' at $LineNo !\n";
	}
	# Time this outgoing URB as now, save the previous time
	$LastUrbTime = $UrbTime;
	$UrbTime = $LineTime;
	# Print time info if desired
	if( $ShowTime ) {
	    printf "+ %.3f (%.3f)\n", $UrbTime, $UrbTime - $LastUrbTime;
	}

	ReadUrb( $UrbDir, $UrbId, $UrbType );
    }
    else {
	die "State error: Unexpected line '$Line' at $LineNo !\n";
    }
}

sub ParseIncoming {
    my $UrbDir = '<-';
    my ( $UrbId, $UrbType );

    # Read and parse the URB direction & number header
    ReadLine() or die "Read error\n";
    if( $Line =~ /<< +URB (\d+) coming back/ ) {
	$UrbId = $1;			# Save the ID number
	# Read and parse the URB type
	ReadLine() or die "Read error\n";
	if( $Line =~ /^-- ?(\S+):/ ) {
	    $UrbType = $1;
	}
	else {
	    die "State error: Unexpected line '$Line' at $LineNo !\n";
	}
	ReadUrb( $UrbDir, $UrbId, $UrbType );
    }
    else {
	die "State error: Unexpected line '$Line' at $LineNo !\n";
    }
}

sub ReadUrb {
    my( $UrbDir, $UrbId, $UrbType ) = @_;

    my %Params;
    my %TerseParams;
    my $Data;

    while( PeekLine() ) {
	# Handle 'key = value' lines;
	if( $Line =~ /^(.*\S)\s*=\s+(.*)/ ) {
	    my $key = $1;
	    my $value = $2;
	    $Params{$key} = $value;
	    # Strip off flag explanations etc for terse version
	    if( $value =~ /^[0-9a-f]+ \(/ ) {
		$value =~ s/ .*//;
	    }
	    if( $value =~ /^00+/ ) {
		$value =~ s/^00+/0/;
	    }
	    $TerseParams{$key} = $value;
	}
	# Handle hex data (eg transfers)
	elsif( $Line =~ /^([0-9a-f ]+)$/ ) {
	    if( $Data ) {
		$Data = "$Data $Line";
	    }
	    else {
		$Data = $Line;
	    }
	}
	# Anything else must be the end of the URB data
	else {
	    last;		# Break out of the loop, ie cleanup and return
	}
	# We only peeked at the line... Now read it so the next peek gets the
	# next one
	ReadLine() or die "Read error!\n";
    }
    # Remap URB type name to something nicer if we can
    my $TypeName = $UrbType;
    if( $UrbTypeMap{$TypeName} ) {
	$TypeName = $UrbTypeMap{$TypeName};
    }

    if( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) {
	# Save vendor IDs as we print them out
	$LastVendor = $TerseParams{'Request'};
	# Put a seperator before request 0x80's to seperate things a bit
	if( $LastVendor eq '80' ) {
	    print "----------------------------------------------\n";
	}
    }

    # Decide whether or not to print anything
    my $DoPrint = 1;
    if( $Quiet && $LastVendor ) {
	if( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) {
	    if( ($LastVendor eq '01') || ($LastVendor eq '81' )) {
		$DoPrint = 0;
	    }
	}
	if( $UrbType eq 'URB_FUNCTION_CONTROL_TRANSFER' ) {
	    if( ($LastVendor eq '01') || ($LastVendor eq '80' )) {
		$DoPrint = 0;
	    }
	}
    }

    if ( $DoPrint ) {
	# Start of line is common
	print "$UrbDir $UrbId $TypeName: ";

	if ( $UrbType eq 'URB_FUNCTION_CONTROL_TRANSFER' ) {
	    print "Buflen=$TerseParams{'TransferBufferLength'}  ";
	    unless( $Quiet ) {
		print "Flags=$TerseParams{'TransferFlags'}  ";
		print "Pipe=$TerseParams{'PipeHandle'}  ";
	    }
	} elsif ( $UrbType eq 'URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE' ) {
	    print "Index=$TerseParams{'Index'}  ";
	    print "Type=$TerseParams{'DescriptorType'}  ";
	    print "Lang=$TerseParams{'LanguageId'}  ";
	} elsif ( $UrbType eq 'URB_FUNCTION_SELECT_CONFIGURATION' ) {
	    # Nothing here yet :)
	} elsif ( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) {
	    print "Req=$TerseParams{'Request'}  ";
	    unless( $Quiet ) {
		print "Value=$TerseParams{'Value'}  ";
		print "Index=$TerseParams{'Index'}  ";
		print "Res Bits=$TerseParams{'RequestTypeReservedBits'}  ";
		print "Pipe=$TerseParams{'PipeHandle'}  " if( $Params{'PipeHandle'});
	    }
	}
	print "\n";

	# Hexdump any setup packets
	if ( $ShowSetup && $Params{'SetupPacket'} ) {
	    HexDump( "   Setup: ", 8, $Params{'SetupPacket'}, 0 );
	}

	# Hexdump any data transferred
	if ( $Data ) {
	    HexDump( "   ", 16, $Data, 1 );
	}
	# In verbose mode print out all the key/values
	if ( $Verbose ) {
	    foreach my $k (sort keys %Params) {
		print "  $k = $Params{$k}\n";
	    }
	    print "------------------\n"
	}
	if( $UrbDir eq '<-' ) {
	    print "\n";		# Extra blank line for readbility
	}
    }
#    else {
#	print "--\n";
#    }
}


#############################################################################
# ReadLine() - Read the next line from the file, skipping cruft and tidying
# up.  
sub ReadLine {
    # If some function peeked ahead, we don't need to actually read the line
    if( $PeekFlag ) {
	$PeekFlag = 0;
	return 1;
    }
    while( <> ) {
	# split out the line number and time fields
	if( /^(\d+)\s+([0-9.]+)\s+(.*)$/ ) {	# "old" usbsnoopy format
	    $LineNo = $1;
	    $LineTime = $2;
	    $Line = $3;
	    $Line =~ s/ : / = /g;		# Convert for easier parsing later
	}
	elsif( /^\[(\d+) ms\] (.*)$/ ) {	# 'new' usbsnoop format
	    $LineTime = $1;
	    $Line = $2;
	    if( $LineNo ) {			# Could line numbers ourself
		$LineNo++;
	    }
	    else {
		$LineNo = 1;			# Count line number ourself
		$FreeStyle = 1;			# Allow 'freestyle' lines
	    }
	}
	elsif( $FreeStyle ) {
	    s/^\s*//;
	    s/^[0-9a-f]+: //;	# Nasty hack to get rid of markers in hex data
	    $Line = $_;
	    if( $Line =~ /^SetupPacket/ ) {
		# Even nastier hack for the way setup packets are dumped
		my $t = <>;
		if( $t ) {
		    $t =~ s/^\s*//;
		    $t =~ s/\s+$//;
		    $t =~ s/^[0-9a-f]+: //;
		    $Line = "$Line $t";
		}
	    }
	    $LineNo++;
	}
	else {
	    die "Parse error!";
	}
	next unless $Line;			# SKIP blank lines
	$Line =~ s/^\s*//;			# Trim leading whitespace
	$Line =~ s/\s+$//;			# Trim trailing whitespace
	next if( $Line =~ /^UsbSnoop/ );	# Skip UsbSnoop internal stuff
	next if( $Line =~ /^fido=/ );
	next if( $Line =~ /^fdo=/ );
	next if( $Line =~ /^pdx=/ );
	next if( $Line =~ /^\d+:\s*$/ );	# Skip hexdump 'count' lines
	#print "$LineNo/$LineTime '$Line'\n";
	return 1;
    }
    $Line = undef;
    return undef;
}

#############################################################################
# PeekLine() - Peek at the next line, but leave it available for reading.
# makes the parsing mess a bit simpler.  NB This overwrite the global $Line
# etc variables.
sub PeekLine {
    my $result = 1;

    # If we already peeked we don't need to peek again
    if( $PeekFlag ) {
	# Handle the case where a previous peek found EOF
	$result = undef unless $Line;
    }
    else {
	$result = ReadLine();
	$PeekFlag = 1;
    }
    return $result;
}


sub HexDump {
    my ($prefix, $linemax, $str, $bool) = @_;

    my @bytes = split( / /, $str );

    my $offset = 0;
    my $size = $#bytes + 1;
    #print "** $str\n";
    while( $size > 0 ) {
	my $rowsize = ($size > $linemax ) ? $linemax : $size;
	printf "%s%04x: ", $prefix, $offset;
	my $i;
	for( $i = 0; $i < $rowsize; $i++ ) {
	    print "$bytes[$i + $offset] ";
	}
	for( ; $i < $linemax; $i++ ) {
	    print "   ";
	}
	print "  ";
	if($bool) {
	  for( $i = 0; $i < $rowsize; $i++ ) {
	    my $c = '.';
	    my $b = $bytes[$i + $offset];
	    if( $b ) {
		  $b = hex $b;	# Convert to decimal
		  if( $b >= 32 && $b < 127 ) {
		    $c = chr $b;
		  }
	    }
	    print $c;
	  }
	}
	print "\n";
	$size -= $rowsize;
	$offset += $rowsize;
    }
}

#############################################################################

sub Usage {
    print<<EOS;

logparse - Try to simplify USBSnoopy logs

 Usage:  logparse [opts] <logfile>\n

Options include:-
    -v		Verbose output
    -q		Be extra quiet
    -s		Show setup packets too
    -t		Show packet times too
EOS
    exit 1;
}

Reply via email to