#!/usr/bin/perl

########################################################
#                                                      #
# COPYRIGHT (C) FUJITSU,LTD. 2001 ALL RIGHTS RESERVED. #
# COPYRIGHT (C) HITACHI,LTD. 2001 ALL RIGHTS RESERVED. #
#                                                      #
# Created by Y.GOTO <y-goto@jp.fujitsu.com>            #
#            T.INDOH <indou.takao@jp.fujitsu.com>      #
#                                                      #
########################################################

use strict;
use English;
use Getopt::Std;

my ($FIXED_LEN_DATA_NUM);
my (@event_data);
my ($event_type, $event_name);
my ($i,$j,$k,$idx);
my ($read_entry_num, $out_entry_num);
my ($buffer);
my (@entry,@entry_idx,@variable_data,@tmp);
my ($arg_inputfile,$arg_entry_num,$arg_cpu_id,$arg_sort,$arg_filter);
my ($time_sec, $time_min, $time_hour, $time_mday, $time_mon, $time_year, $time_wday, $time_yday, $time_isdst);
my (@time_wday_name,@time_mon_name);

my ($MAGIC,$REC_ID,$SIZE,$FORMAT,$EVENT_TYPE);
my ($FACILITY,$SEVERITY,$UID,$GID,$PID);
my ($PGRP,$TIME_SEC,$TIME_USEC,$FLAGS,$THREAD,$CPU,$VARIABLE_DATA);
my ($ARG1_H,$ARG1_L,$ARG2_H,$ARG2_L,$ARG3_H,$ARG3_L,$ARG4_H,$ARG4_L);
my ($EDATA_ID_MIN,$EDATA_ID_MAX);

#
# index of data in the entry
#
	# fixed length part
	$MAGIC=0;
	$REC_ID=1;
	$SIZE=2;
	$FORMAT=3;
	$EVENT_TYPE=4;
	$FACILITY=5;
	$SEVERITY=6;
	$UID=7;
	$GID=8;
	$PID=9;
	$PGRP=10;
	$TIME_SEC=11;
	$TIME_USEC=12;
	$FLAGS=13;
	$THREAD=14;
	$CPU=15;
	$VARIABLE_DATA=16;

	$FIXED_LEN_DATA_NUM=16; # the number of data in the fixed length record

	# variable length part
	$ARG1_L=0;
	$ARG1_H=1;
	$ARG2_L=2;
	$ARG2_H=3;
	$ARG3_L=4;
	$ARG3_H=5;
	$ARG4_L=6;
	$ARG4_H=7;

#
# event data
#	@event_data[0x0001]=({"event_name" => event name,
#	                      "filter"     => filter on/off,
#	                      "arg1"       => information about argument1,
#	                      "arg2"       => information about argument2,
#	                      "arg3"       => information about argument3,
#	                      "arg4"       => information about argument4});
#

	@event_data[0x0001]=({"event_name" => "context_switch",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to task_struct(prev)",
	                      "arg2"       => "pointer to task_struct(next)",
	                      "arg3"       => "process state/process count",
	                      "arg4"       => ""});
	@event_data[0x0002]=({"event_name" => "process_wakeup",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to wakeup-process(p)",
	                      "arg2"       => "synchronous",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0003]=({"event_name" => "process_sigsend",
	                      "filter"     => "off",
	                      "arg1"       => "signal number(sig)",
	                      "arg2"       => "pointer to process to which signal is sent",
	                      "arg3"       => "pointer to info structure(info)",
	                      "arg4"       => ""});
	@event_data[0x0004]=({"event_name" => "kernel_thread",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to kernel thread(fn)",
	                      "arg2"       => "argument of kernel thread(arg)",
	                      "arg3"       => "flag",
	                      "arg4"       => ""});
	@event_data[0x0010]=({"event_name" => "interrupt_hardware_entry",
	                      "filter"     => "off",
	                      "arg1"       => "IRQ number(irq)",
	                      "arg2"       => "interrupt status(status)",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0012]=({"event_name" => "interrupt_tasklethi_entry",
	                      "filter"     => "off",
	                      "arg1"       => "action address(t->func)",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0014]=({"event_name" => "interrupt_tasklet_entry",
	                      "filter"     => "off",
	                      "arg1"       => "action address(t->func)",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0016]=({"event_name" => "interrupt_bh_entry",
	                      "filter"     => "off",
	                      "arg1"       => "interrupt type(nr)",
	                      "arg2"       => "action address(bh_base)",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0020]=({"event_name" => "exception_entry",
	                      "filter"     => "off",
	                      "arg1"       => "exception-handler address(edi)",
	                      "arg2"       => "error code(esi)",
	                      "arg3"       => "exception occurred address(eip)",
	                      "arg4"       => ""});
	@event_data[0x0021]=({"event_name" => "exception_exit",
	                      "filter"     => "off",
	                      "arg1"       => "exception-handler address(edi)",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0030]=({"event_name" => "system_call_entry",
	                      "filter"     => "off",
	                      "arg1"       => "call number",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0031]=({"event_name" => "system_call_exit",
	                      "filter"     => "off",
	                      "arg1"       => "call number",
	                      "arg2"       => "return value(errno)",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0040]=({"event_name" => "fs_devrw",
	                      "filter"     => "off",
	                      "arg1"       => "buffer(bh)",
	                      "arg2"       => "READ/WRITE(rw)",
	                      "arg3"       => "the number of block transfered(nr)",
	                      "arg4"       => ""});
	@event_data[0x0041]=({"event_name" => "fs_devend",
	                      "filter"     => "off",
	                      "arg1"       => "buffer(bf)",
	                      "arg2"       => "uptodate",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0042]=({"event_name" => "fs_devwait",
	                      "filter"     => "off",
	                      "arg1"       => "buffer(bh)",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0050]=({"event_name" => "mem_swapout",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page swapped-out",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0051]=({"event_name" => "mem_swapin",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page swapped-in",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0052]=({"event_name" => "mem_do_nopage",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page allocated",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0053]=({"event_name" => "mem_do_wppage",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0054]=({"event_name" => "mem_wait_page",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0055]=({"event_name" => "mem_get_freepage",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page",
	                      "arg2"       => "type of page(gfp_mask)",
	                      "arg3"       => "the number of page(order)",
	                      "arg4"       => "call address"});
	@event_data[0x0056]=({"event_name" => "mem_get_zeropage",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page",
	                      "arg2"       => "type of page(gfp_mask)",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x0057]=({"event_name" => "mem_freepage",
	                      "filter"     => "off",
	                      "arg1"       => "pointer to page",
	                      "arg2"       => "the number of page(order)",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x0058]=({"event_name" => "mem_vmalloc",
	                      "filter"     => "off",
	                      "arg1"       => "address(addr)",
	                      "arg2"       => "size",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x0059]=({"event_name" => "mem_vfree",
	                      "filter"     => "off",
	                      "arg1"       => "address(addr)",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x005a]=({"event_name" => "mem_cache_create",
	                      "filter"     => "off",
	                      "arg1"       => "name",
	                      "arg2"       => "size",
	                      "arg3"       => "cachep",
	                      "arg4"       => ""});
	@event_data[0x005b]=({"event_name" => "mem_cache_alloc",
	                      "filter"     => "off",
	                      "arg1"       => "cachep",
	                      "arg2"       => "flags",
	                      "arg3"       => "objp",
	                      "arg4"       => "call address"});
	@event_data[0x005c]=({"event_name" => "mem_malloc",
	                      "filter"     => "off",
	                      "arg1"       => "size",
	                      "arg2"       => "flags",
	                      "arg3"       => "objp",
	                      "arg4"       => "call address"});
	@event_data[0x005d]=({"event_name" => "mem_cache_free",
	                      "filter"     => "off",
	                      "arg1"       => "cachep",
	                      "arg2"       => "objp",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x005e]=({"event_name" => "mem_free",
	                      "filter"     => "off",
	                      "arg1"       => "objp",
	                      "arg2"       => "call address",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0060]=({"event_name" => "net_pktsend",
	                      "filter"     => "off",
	                      "arg1"       => "skb",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0061]=({"event_name" => "net_pktsendi",
	                      "filter"     => "off",
	                      "arg1"       => "h",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0062]=({"event_name" => "net_pktrecv",
	                      "filter"     => "off",
	                      "arg1"       => "skb",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0063]=({"event_name" => "net_pktrecvi",
	                      "filter"     => "off",
	                      "arg1"       => "h",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0064]=({"event_name" => "net_socketif",
	                      "filter"     => "off",
	                      "arg1"       => "call",
	                      "arg2"       => "args",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0070]=({"event_name" => "sysv_ipc",
	                      "filter"     => "off",
	                      "arg1"       => "call/first",
	                      "arg2"       => "second/third",
	                      "arg3"       => "*ptr",
	                      "arg4"       => ""});
	@event_data[0x0080]=({"event_name" => "spin_lock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "lock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0081]=({"event_name" => "spin_trylock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "lock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0082]=({"event_name" => "spin_unlock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "lock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0083]=({"event_name" => "write_lock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "rwlock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0084]=({"event_name" => "write_trylock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "rwlock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0085]=({"event_name" => "write_unlock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "rwlock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0086]=({"event_name" => "read_lock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "rwlock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0087]=({"event_name" => "read_unlock",
	                      "filter"     => "off",
	                      "arg1"       => "call address",
	                      "arg2"       => "rwlock",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0090]=({"event_name" => "portin",
	                      "filter"     => "off",
	                      "arg1"       => "port address/bite-width",
	                      "arg2"       => "value",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x0091]=({"event_name" => "portout",
	                      "filter"     => "off",
	                      "arg1"       => "port address/bite-width",
	                      "arg2"       => "value",
	                      "arg3"       => "call address",
	                      "arg4"       => ""});
	@event_data[0x0092]=({"event_name" => "panic",
	                      "filter"     => "off",
	                      "arg1"       => "address of argument",
	                      "arg2"       => "call address",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0093]=({"event_name" => "printk",
	                      "filter"     => "off",
	                      "arg1"       => "address of argument",
	                      "arg2"       => "call address",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x00a0]=({"event_name" => "timer_run",
	                      "filter"     => "off",
	                      "arg1"       => "function address(fn)",
	                      "arg2"       => "parameter(data)",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x00a1]=({"event_name" => "timer_add",
	                      "filter"     => "off",
	                      "arg1"       => "timer",
	                      "arg2"       => "timer->expires",
	                      "arg3"       => "timer->function",
	                      "arg4"       => "timer->data"});
	@event_data[0x00a2]=({"event_name" => "timer_mod",
	                      "filter"     => "off",
	                      "arg1"       => "timer",
	                      "arg2"       => "timer->expires",
	                      "arg3"       => "timer->function",
	                      "arg4"       => "timer->data"});
	@event_data[0x00a3]=({"event_name" => "timer_del",
	                      "filter"     => "off",
	                      "arg1"       => "timer",
	                      "arg2"       => "timer->expires",
	                      "arg3"       => "timer->function",
	                      "arg4"       => "timer->data"});
	@event_data[0x00a4]=({"event_name" => "timer_del_sync",
	                      "filter"     => "off",
	                      "arg1"       => "timer",
	                      "arg2"       => "timer->expires",
	                      "arg3"       => "timer->function",
	                      "arg4"       => "timer->data"});
	@event_data[0x0f00]=({"event_name" => "lkst_init",
	                      "filter"     => "off",
	                      "arg1"       => "data",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0f08]=({"event_name" => "lkst_mset_xchg",
	                      "filter"     => "off",
	                      "arg1"       => "old makset id",
	                      "arg2"       => "new maskset id",
	                      "arg3"       => "pointer to old maskset",
	                      "arg4"       => "pointer to new maskset"});
	@event_data[0x0f10]=({"event_name" => "lkst_buff_shift",
	                      "filter"     => "off",
	                      "arg1"       => "old buffer id",
	                      "arg2"       => "next buffer id",
	                      "arg3"       => "pointer to old buffer",
	                      "arg4"       => "pointer to next buffer"});
	@event_data[0x0f11]=({"event_name" => "lkst_buff_ovflow",
	                      "filter"     => "off",
	                      "arg1"       => "",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0f12]=({"event_name" => "lkst_buff_high",
	                      "filter"     => "off",
	                      "arg1"       => "",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0f18]=({"event_name" => "lkst_sync_time",
	                      "filter"     => "off",
	                      "arg1"       => "",
	                      "arg2"       => "",
	                      "arg3"       => "",
	                      "arg4"       => ""});
	@event_data[0x0f19]=({"event_name" => "lkst_sync_uid",
	                      "filter"     => "off",
	                      "arg1"       => "ruid",
	                      "arg2"       => "",
	                      "arg3"       => "pointer to current task_struct",
	                      "arg4"       => ""});
	@event_data[0x0f1a]=({"event_name" => "lkst_sync_gid",
	                      "filter"     => "off",
	                      "arg1"       => "rgid",
	                      "arg2"       => "",
	                      "arg3"       => "pointer to current task_struct",
	                      "arg4"       => ""});
	@event_data[0x0f1b]=({"event_name" => "lkst_sync_pgid",
	                      "filter"     => "off",
	                      "arg1"       => "pid",
	                      "arg2"       => "pgrp",
	                      "arg3"       => "pointer to task_struct",
	                      "arg4"       => "leader"});
	@event_data[0x0f1c]=({"event_name" => "lkst_sync_tid",
	                      "filter"     => "off",
	                      "arg1"       => "tid(pid)",
	                      "arg2"       => "",
	                      "arg3"       => "pointer to current task_struct",
	                      "arg4"       => ""});
	@event_data[0x0ffe]=({"event_name" => "overwritten_record",
	                      "filter"     => "off",
	                      "arg1"       => "old arg1",
	                      "arg2"       => "old arg2",
	                      "arg3"       => "old arg3",
	                      "arg4"       => "old event_type"});
	$EDATA_ID_MIN=0x01;
	$EDATA_ID_MAX=0x0ffe;

#
# the name of wday and month
#
	@time_wday_name=qw(Sun Mon Tue Wed Thu Fri Sat);
	@time_mon_name =qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);

#
#	get argument
#
	getarg();


	if ($arg_inputfile eq "-") {
		*BIN_FILE = *STDIN;
	}
	else {
		if(!open(BIN_FILE,$arg_inputfile)){
			die("$PROGRAM_NAME: can't open:$arg_inputfile\n");
		}
	}


#
#	read data
#
	# read log header
	#   (uint)log_magic                  /* Magic number indicating log file */
	#   (long)log_version                /* Event logging version */
	#   (posix_log_recid_t)last_recId    /* Last recid in log: used by evlogd */
	#   (off_t)reserved1
	#   (uint)log_generation             /* Changes during log maintenance */
	if(!read(BIN_FILE,$buffer,20)){
		die("$PROGRAM_NAME: can't read log buffer\n");
	}

	$i=0;
LOOP1:
	while(1){ # infinite loop
		# read fixed length part
		for ($j=0;$j<$FIXED_LEN_DATA_NUM;$j++){
			if(!read(BIN_FILE,$buffer,4)){
				last LOOP1;
			}
			$entry[$i][$j]=unpack("L",$buffer);
		}
		# read variable length part
		if($entry[$i][$SIZE] > 0x80000000){
			die("$PROGRAM_NAME: Negative length of variable data\n");
		}
		if(!read(BIN_FILE,$entry[$i][$j],$entry[$i][$SIZE])){
			last LOOP1;
		}
		$i++;
	}
	close(BIN_FILE);
	$read_entry_num=$i;
	if($arg_entry_num < 0){
		$arg_entry_num = $read_entry_num;
	}

#
#	sort data
#
	for ($i=0;$i<$#entry;$i++){
		push @tmp, $entry[$i][$REC_ID];
	}
	if($arg_sort eq "descending"){
		@entry_idx = sort { @tmp[$b] <=> @tmp[$a] } 0..$#entry - 1
	}
	else{
		@entry_idx = sort { @tmp[$a] <=> @tmp[$b] } 0..$#entry - 1
	}

#
#	display data
#
	for($i=0, $out_entry_num=0;$i<$read_entry_num;$i++){

		$idx = @entry_idx[$i];

		#skip lkst info-record
		if($entry[$idx][$REC_ID] == 0)
		{
			next;
		}

		if(($arg_cpu_id >= 0)&&($arg_cpu_id != $entry[$idx][$CPU]))
		{
			next;
		}
		$event_type = $entry[$idx][$EVENT_TYPE];

		#event filter

		if($arg_filter eq "on"){
			if($event_data[$event_type]{filter} ne "on"){
				next;
			}
		}

		#display event_type

		$event_name = $event_data[$event_type]{event_name};
		if($event_name eq "" ){
						# event_data undefined ?

			printf("event_type=0x%08x\n", $event_type);

		}else{
						# display event name

			printf("event_type=%s\n", $event_name);
		}

		#display cpu pid time

		($time_sec, $time_min, $time_hour, $time_mday, $time_mon, $time_year, $time_wday)
		= localtime($entry[$idx][$TIME_SEC]);

		printf("\tcpu=%02d, pid=%08d\n", $entry[$idx][$CPU], $entry[$idx][$PID]);
		printf("\ttime=%s %s %2d %02d:%02d:%02d.%09d %d\n",
			$time_wday_name[$time_wday], $time_mon_name[$time_mon], $time_mday,
			$time_hour, $time_min, $time_sec, $entry[$idx][$TIME_USEC], $time_year + 1900);

		#display variable length part
		$k=0;
		for ($j=0;$j<=$ARG4_H;$j++){
			$variable_data[$j]=unpack("L", substr($entry[$idx][$VARIABLE_DATA], $k, 4));
			$k+=4;
		}
		if(($event_data[$event_type]{arg1} ne "")||
		   ($event_name eq "")){
			printf("\targ1=0x%08x 0x%08x : %s\n",
					$variable_data[$ARG1_H], $variable_data[$ARG1_L], $event_data[$event_type]{arg1});
		}
		if(($event_data[$event_type]{arg2} ne "")||
		   ($event_name eq "")){
			printf("\targ2=0x%08x 0x%08x : %s\n",
					$variable_data[$ARG2_H], $variable_data[$ARG2_L], $event_data[$event_type]{arg2});
		}
		if(($event_data[$event_type]{arg3} ne "")||
		   ($event_name eq "")){
			printf("\targ3=0x%08x 0x%08x : %s\n",
					$variable_data[$ARG3_H], $variable_data[$ARG3_L], $event_data[$event_type]{arg3});
		}
		if(($event_data[$event_type]{arg4} ne "")||
		   ($event_name eq "")){
			printf("\targ4=0x%08x 0x%08x : %s\n",
					$variable_data[$ARG4_H], $variable_data[$ARG4_L], $event_data[$event_type]{arg4});
		}

		print "\n";
		$out_entry_num++;
		if($out_entry_num >= $arg_entry_num){
			last;
		}
	}

	if($out_entry_num == 0){
		die("No data.\n");
	}

#
# get argument
#
sub getarg
{
my (%options);
my (@tmp_event_list);
my ($tmp_filter);
my ($tmp_arg);

	if (@ARGV < 1){
		usage();
		exit 1;
	}

	$arg_inputfile="";
	$arg_entry_num=-1;
	$arg_sort="descending";
	$arg_cpu_id=-1;
	$arg_filter="";
	$tmp_filter="";
	$tmp_arg="";

	#use Getopt::Std;
	if(!getopts('c:e:hn:r', \%options)){
		print STDERR "$PROGRAM_NAME: getopts error\n\n";
		usage();
		exit 1;
	}

	# -h option
	if($options{h}){
		usage("all");
		exit 0;
	}

	# -c option
	if($options{c}){
		if($options{c} =~ /^\d+$/){
			$arg_cpu_id=$options{c};
		}
		else{
			print STDERR "$PROGRAM_NAME: invalid argument $options{c}\n\n";
			usage();
			exit 1;
		}
	}

	# -e option
	if($options{e}){
		$arg_filter="on";
		@tmp_event_list=split(/,/,$options{e});

		for($i=0; $i<=@tmp_event_list; $i++){
			if($tmp_event_list[$i] =~ /^!(.*)/){
				$tmp_filter="off";
				$tmp_arg=$1;
			}
			else{
				$tmp_filter="on";
				$tmp_arg=$tmp_event_list[$i];
			}

			if($tmp_arg eq "all"){
				for($j=$EDATA_ID_MIN; $j<=$EDATA_ID_MAX; $j++){
					$event_data[$j]{filter}=$tmp_filter;
				}
				next;
			}

			# find event name
			for($j=$EDATA_ID_MIN; $j<=$EDATA_ID_MAX; $j++){
				if($event_data[$j]{event_name} eq $tmp_arg){
					$event_data[$j]{filter}=$tmp_filter;
					last;
				}
			}

			if($j>$EDATA_ID_MAX){
				# can't find event name
				die("$PROGRAM_NAME: unknown event name: $tmp_arg\n\n");
			}
		}
	}

	# -n option
	if($options{n}){
		if($options{n} =~ /^\d+$/){
			$arg_entry_num=$options{n};
		}
		else{
			print STDERR "$PROGRAM_NAME: invalid argument $options{n}\n\n";
			usage();
			exit 1;
		}
	}

	# -r option
	$arg_sort="ascending" if($options{r});

	# operand
	$arg_inputfile = shift @ARGV;

	if($arg_inputfile eq ""){
		print STDERR "$PROGRAM_NAME: no input file\n\n";
		usage();
		exit 1;
	}

	if(@ARGV != 0){
		print STDERR "$PROGRAM_NAME: invalid argument $ARGV[0]\n\n";
		usage();
		exit 1;
	}
}


#
# usage
#
sub usage
{
my ($idx);
my ($all);

	($all) = @_;

	print STDERR "usage: \n";
	print STDERR "$PROGRAM_NAME [options] trace_bin_file\n";
	print STDERR "   -c cpu_id             cpu id\n";
	print STDERR "   -e event_name ...     event filter\n";
	if($all eq "all"){
		print STDERR "                         The event_name which can be specified is as follows.\n";
		for($idx=$EDATA_ID_MIN; $idx<=$EDATA_ID_MAX; $idx++){
			if($event_data[$idx]{event_name} ne ""){
				print STDERR "                           $event_data[$idx]{event_name}\n";
			}
		}
		print STDERR "                           all\n";
	}
	print STDERR "   -h                    help\n";
	print STDERR "   -n entry_num          the number of output entry\n";
	print STDERR "   -r                    reverse the order of output record\n";
	print STDERR "                         (default : descending sort)\n";
}
