#!/usr/bin/perl

use IO::Handle;

$naptime = 1;

open(LOGFILE, "/var/log/messages") or die "can't open /var/log/messages: $!";
for(;;) {
	while(<LOGFILE>) { 
		if(/robes.*55 44 33 22/) {
			@fields = split;
			$i = 0;
			while($i <= $#fields) {
				if(($fields[$i] eq '55') &&
				   ($fields[$i+1] eq '44') &&
				   ($fields[$i+2] eq '33') &&
				   ($fields[$i+3] eq '22')) {
					$str_start = $i+4;
					$j = $str_start;
					@value = ();
					while($j <= $#fields) {
					    # a new line is preceded by
					    # 7 x x and starts with 55
					    if(($fields[$j] eq '7') &&
					       ($fields[$j+3] eq '55')) {
						$j += 3;
					    }
					    $str_val = strval_l($j, @fields);
					    if($str_val eq '22334455') { # new line
						$i = $j-1; 
						print "\n";	
						last;
					    }
					    if($str_val eq '55443322') {
						$str_val = strval_l($j+4, @fields);
						$num = hex($str_val);
						printf "%d", $num;
						$j+=8;
					    } elsif($str_val eq '66554433') {
						$str_val = strval_l($j+4, @fields);
						$num = hex($str_val);
						printf "%u", $num;
						$j+=8;
					    } elsif($str_val eq '77665544') {
						$str_val = strval_l($j+4, @fields);
						$num = hex($str_val);
						printf "0x%x", $num;
						$j+=8;
					    } else {
						print chr(hex($str_val));
						$j+=4;
					    }
					}
				}
				$i++	
			}
			print "\n";	
		} elsif(/obes\(0,0\)/) {
		    $stacktrace = trim($');
		    @fields = split /\s+/, $stacktrace;
		    print_stacktrace(@fields);
		}
	}
	sleep $naptime;
	LOGFILE->clearerr();
}

sub strval_l {
    my($j, @fields) = @_;
    @value = ();
    $value[0] = $fields[$j];
    $value[1] = $fields[$j+1];
    $value[2] = $fields[$j+2];
    $value[3] = $fields[$j+3];
    @value = reverse(@value);
    $str_val = join "", @value;
}

sub strval_s {
    my($j, @fields) = @_;
    @value = ();
    $value[0] = $fields[$pos];
    $value[1] = $fields[$pos+1];
    # unsigned short, only first 2
    $value[2] = '0';
    $value[3] = '0';
    @value = reverse(@value);
    $str_val = join "", @value;
}

sub print_stacktrace {
    my(@fields) = @_;

    print "stacktrace:\n";
    $i = 0;
    # first field always 1 (TOKEN_ASCII_LOG)
    # second field pgm name strlen  
    if($fields[0] =~ /=/) { # discard headers
	$pos = 2;
    }
    else {
	$pos = 1;
    }
    $num = hex($fields[$pos]);
    $i = 0;
    print "PROGRAM NAME: ";
    while($i < $num) {
	if($fields[0] =~ /=/) { # discard headers
	    # string starts at position 4
	    print chr(hex($fields[4+$i++]));
	}
	else {
	    # string starts at position 3
	    print chr(hex($fields[3+$i++]));
	}
    }			
    print "\n";
    
    if($fields[0] =~ /=/) { # discard headers
	$pos = 4 + $num;
    }
    else {
	$pos = 3 + $num;
    }
    $str_val = strval_l($pos, @fields);
    $num = hex($str_val);
    printf "OFFSET: %x\n", $num;

    $pos += 4;
    $str_val = strval_s($pos, @fields);
    $num = hex($str_val);
    printf "ID: %d\n", $num;
	
    $pos += 2;
    $str_val = strval_s($pos, @fields);
    $num = hex($str_val);
    printf "MAJOR: %d\n", $num;
	
    $pos += 2;
    $str_val = strval_s($pos, @fields);
    $num = hex($str_val);
    printf "MINOR: %d\n", $num;

    $pos += 2;
    $str_val = strval_l($pos, @fields);
    $num = hex($str_val);
    printf "FIELD: 0x%x\n", $num;

    $pos += 4;
    # field always 2 (TOKEN_STACK_TRACE), skip it
    $pos += 1;

    $str_val = strval_s($pos, @fields);
    $num = hex($str_val);
    printf "STACK TRACE REPETITION: %d\n", $num;
    $pos += 2;
    $num_stacktraces = $num;

    $i = 0;
    while($i < $num_stacktraces) {
	$str_val = strval_l($pos, @fields);
	$num = hex($str_val);
	printf "  EXCEPTION CODE: 0x%x\n", $num;

	$pos += 4;
	$str_val = strval_l($pos, @fields);
	$num = hex($str_val);
	printf "  EXCEPTION ADDRESS: %d\n", $num;

	$pos += 4;
	$str_val = strval_l($pos, @fields);
	$num = hex($str_val);
	printf "  EX PARAM1: 0x%x\n", $num;

	$pos += 4;
	$str_val = strval_l($pos, @fields);
	$num = hex($str_val);
	printf "  EX_PARAM2: 0x%x\n", $num;

	$pos += 4;
	# field always 3 (TOKEN_STACK_FRAME), skip it
	$pos += 1;

	$str_val = strval_s($pos, @fields);
	$num = hex($str_val);
	printf "  STACK FRAME REPETITION: %d\n", $num;
	$pos += 2;

	$num_stackframes = $num;
			
	$j = 0;
	while($j < $num_stackframes) {
	    $str_val = strval_l($pos, @fields);
	    $num = hex($str_val);
	    printf "    CALLED ADDRESS: 0x%x\n", $num;
	    $pos += 4;

	    $str_val = strval_l($pos, @fields);
	    $num = hex($str_val);
	    printf "    RETURN ADDRESS: 0x%x\n", $num;
	    $pos += 4;
			    
	    # field always 4 (TOKEN_RPN_ENTRY), skip it
	    $pos += 1;

	    $str_val = strval_s($pos, @fields);
	    $num = hex($str_val);
	    printf "    RPN STACK ENTRIES: %d\n", $num;
	    $pos += 2;

	    $num_entries = $num;

	    $k = 0;
	    while($k < $num_entries) {
		$str_val = strval_l($pos, @fields);
		$num = hex($str_val);
		printf "      STACK ENTRY: 0x%x\n", $num;
		$pos += 4;
		
		$k++;
	    }

	    # field always 5 (TOKEN_LV_ENTRY), skip it
	    $pos += 1;

	    $str_val = strval_s($pos, @fields);
	    $num = hex($str_val);
	    printf "    LV ENTRIES: %d\n", $num;
	    $pos += 2;

	    $num_entries = $num;

	    $k = 0;
	    while($k < $num_entries) {
		$str_val = strval_l($pos, @fields);
		$num = hex($str_val);
		printf "      LV ENTRY: 0x%x\n", $num;
		$pos += 4;
		
		$k++;
	    }

	    # field always 6 (TOKEN_GV_ENTRY), skip it
	    $pos += 1;

	    $str_val = strval_s($pos, @fields);
	    $num = hex($str_val);
	    printf "    GV ENTRIES: %d\n", $num;
	    $pos += 2;

	    $num_entries = $num;

	    $k = 0;
	    while($k < $num_entries) {
		$str_val = strval_l($pos, @fields);
		$num = hex($str_val);
		printf "      GV ENTRY: 0x%x\n", $num;
		$pos += 4;
		
		$k++;
	    }
	    $j++;
	}
	$i++;
    }
}

sub trim {
    my @out = @_;
    for(@out) {
	s/^\s+//;
	s/\s+$//;
    }

    return wantarray ? @out : $out[0];
}
