os/kernelhwsrv/kerneltest/e32utils/trace/btracevw.pl
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
#
sl@0
     2
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
# All rights reserved.
sl@0
     4
# This component and the accompanying materials are made available
sl@0
     5
# under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
# which accompanies this distribution, and is available
sl@0
     7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
#
sl@0
     9
# Initial Contributors:
sl@0
    10
# Nokia Corporation - initial contribution.
sl@0
    11
#
sl@0
    12
# Contributors:
sl@0
    13
#
sl@0
    14
# Description:
sl@0
    15
#
sl@0
    16
sl@0
    17
#!/usr/bin/perl
sl@0
    18
sl@0
    19
use File::Find;
sl@0
    20
use File::Spec::Functions;
sl@0
    21
sl@0
    22
sl@0
    23
	my $TraceFileName;
sl@0
    24
	
sl@0
    25
	my $PrintFlagFilePos = 0;
sl@0
    26
	my $PrintFlagHdrLen = 0;
sl@0
    27
	my $PrintFlagHdrFlags = 0;
sl@0
    28
	my $PrintFlagFormatString = 0;
sl@0
    29
	my $VerboseMode = 0;
sl@0
    30
	my $RawMode = 0;
sl@0
    31
	my $FormatIdIsSubCategory = 0;
sl@0
    32
	my $OutputSawDictionaryMode = 0;
sl@0
    33
	
sl@0
    34
	# for the category range 0-191, the format string is indexed by the category & subcategory
sl@0
    35
	%FormatTables = 
sl@0
    36
		(
sl@0
    37
		0 => 			# ERDebugPrintf
sl@0
    38
			{
sl@0
    39
			0 => "ThreadId %h, %s",
sl@0
    40
			},
sl@0
    41
	
sl@0
    42
		1 => 			# ERKernPrintf
sl@0
    43
			{
sl@0
    44
			0 => "ThreadId %h, %s",
sl@0
    45
			},
sl@0
    46
sl@0
    47
		3 =>			# EThreadIdentification
sl@0
    48
			{	
sl@0
    49
			0 => "ENanoThreadCreate, NThread %x",
sl@0
    50
			1 => "ENanoThreadDestroy, NThread %x",
sl@0
    51
			2 => "EThreadCreate, NThread %x, DProcess %x, name %s",
sl@0
    52
			3 => "EThreadDestroy, NThread %x, DProcess %x, Id %x",
sl@0
    53
			4 => "EThreadName, NThread %x, DProcess %x, name %s",
sl@0
    54
			5 => "EProcessName, NThread %x, DProcess %x, name %s",
sl@0
    55
			6 => "EThreadId, NThread %x, DProcess %x, Id %x",
sl@0
    56
			7 => "EProcessCreate, DProcess %x",
sl@0
    57
			8 => "EProcessDestroy, DProcess %x",
sl@0
    58
			},
sl@0
    59
		);
sl@0
    60
sl@0
    61
	my @typedefs;
sl@0
    62
	my @members;
sl@0
    63
	my %values	= (
sl@0
    64
#		UTF::KInitialClientFormat		=>	{type=>"TFormatId", size=>2, value=>512}
sl@0
    65
		KMaxTUint8						=> {type=>"TUint8", size=>1, value=>255},
sl@0
    66
		KMaxTUint16						=> {type=>"TUint16", size=>2, value=>65535}
sl@0
    67
	);
sl@0
    68
	my %macros;
sl@0
    69
	my @classes;
sl@0
    70
	my @enums;
sl@0
    71
	my %formatStrings;		# each enum may have it's own format string
sl@0
    72
	my %formatCategories;	# each enum may have it's own format category
sl@0
    73
	
sl@0
    74
	my %filescope;
sl@0
    75
	$filescope{file}=1;
sl@0
    76
	undef $filescope{name};	
sl@0
    77
sl@0
    78
	$filescope{typedefs}=\@typedefs;
sl@0
    79
	$filescope{members}=\@members;
sl@0
    80
	$filescope{values}=\%values;
sl@0
    81
	$filescope{macros} = \%macros;
sl@0
    82
	$filescope{FormatTables} = \%FormatTables;
sl@0
    83
	
sl@0
    84
	$filescope{classes} = \@classes;
sl@0
    85
	$filescope{enums} = \@enums;
sl@0
    86
sl@0
    87
	$filescope{formatStrings} =\%formatStrings;
sl@0
    88
	$filescope{formatCategories} = \%formatCategories;
sl@0
    89
	
sl@0
    90
		
sl@0
    91
		
sl@0
    92
	if (@ARGV == 0)
sl@0
    93
  		{
sl@0
    94
  		print "BTraceVw.pl \n";
sl@0
    95
  		print "An unsupported utility which extracts UTrace-style format-strings\n";
sl@0
    96
  		print "from header files & uses these to decode a BTrace output file\n";
sl@0
    97
  		print "Syntax : BTraceVw.pl [-v] [-r] [-sd] [-i <IncFilePath>] [<BTrace file>]\n";
sl@0
    98
  		print "where  : -v  = verbose mode\n";
sl@0
    99
  		print "       : -r  = raw output mode\n";
sl@0
   100
  		print "       : -sd = produce SAW trace viewer dictionary file\n";
sl@0
   101
  		print "       :       this file then needs to be merged into the 'com.symbian.analysis.trace.ui.prefs' file\n";
sl@0
   102
  		print "       :       located under the carbide workspace directory\n";
sl@0
   103
		print "\n";
sl@0
   104
  		
sl@0
   105
		print "e.g. (this decodes a trace file & produces a comma-separated output file) : \n";
sl@0
   106
		print "btracevw.pl -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/f32tracedef.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefsrv.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefile.h trace.utf >trace.csv\n";
sl@0
   107
		print "\n";
sl@0
   108
		print "e.g. (this overwrites the SAW dictioany file) : \n";
sl@0
   109
		print "btracevw.pl -sd -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/f32tracedef.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefsrv.h -i /os/kernelhwsrv/userlibandfileserver/fileserver/inc/utraceefile.h >com.symbian.analysis.trace.ui.prefs\n";
sl@0
   110
  		
sl@0
   111
		exit;
sl@0
   112
		}
sl@0
   113
sl@0
   114
	while (@ARGV > 0)
sl@0
   115
		{
sl@0
   116
		
sl@0
   117
		if ($ARGV[0] eq "-i")
sl@0
   118
	        {
sl@0
   119
	        shift @ARGV;
sl@0
   120
		    ($FilePath) = @ARGV;
sl@0
   121
	        shift @ARGV;
sl@0
   122
sl@0
   123
	        undef @incFiles;
sl@0
   124
		    @incFiles;
sl@0
   125
		
sl@0
   126
		    find sub { push @incFiles, $File::Find::name if m/\.h$/i;}, $FilePath ;
sl@0
   127
		    foreach $incFile (@incFiles)
sl@0
   128
		        {
sl@0
   129
				H2Trace($incFile, \%filescope);
sl@0
   130
		        }
sl@0
   131
	        }
sl@0
   132
		elsif ($ARGV[0] eq "-r")
sl@0
   133
	        {
sl@0
   134
		    $RawMode = 1;
sl@0
   135
   	        shift @ARGV;
sl@0
   136
	        }
sl@0
   137
		elsif ($ARGV[0] eq "-sd")
sl@0
   138
	        {
sl@0
   139
		    $OutputSawDictionaryMode = 1;
sl@0
   140
   	        shift @ARGV;
sl@0
   141
	        }
sl@0
   142
		elsif ($ARGV[0] eq "-v")
sl@0
   143
	        {
sl@0
   144
		    $VerboseMode = 1;
sl@0
   145
   	        shift @ARGV;
sl@0
   146
	        }
sl@0
   147
	    else
sl@0
   148
	    	{
sl@0
   149
			$TraceFileName = "$ARGV[0]";
sl@0
   150
	        shift @ARGV;
sl@0
   151
	    	}
sl@0
   152
        }
sl@0
   153
		
sl@0
   154
	if ($VerboseMode)
sl@0
   155
		{
sl@0
   156
		dump_scope(\%filescope);
sl@0
   157
		PrintFormatTables(\%FormatTables);
sl@0
   158
		}
sl@0
   159
	if ($OutputSawDictionaryMode)
sl@0
   160
		{
sl@0
   161
		OutputSawDictionary(\%FormatTables);
sl@0
   162
		}
sl@0
   163
sl@0
   164
    if (defined ($TraceFileName))
sl@0
   165
        {
sl@0
   166
        ReadTraceFile($RawMode);
sl@0
   167
        }
sl@0
   168
sl@0
   169
        
sl@0
   170
        
sl@0
   171
        
sl@0
   172
sub ReadTraceFile($)
sl@0
   173
    {
sl@0
   174
	(my $RawMode) = @_;
sl@0
   175
#	print "Trace file is $TraceFileName, RawMode $RawMode, VerboseMode $VerboseMode\n\n";
sl@0
   176
sl@0
   177
	open (LOGFILE, "<$TraceFileName") or die "Can't open $TraceFileName: $!\n";
sl@0
   178
	binmode (LOGFILE);
sl@0
   179
sl@0
   180
	my $val = 0;
sl@0
   181
sl@0
   182
sl@0
   183
	# enum TFlags from e32btrace.h
sl@0
   184
	$EHeader2Present	= 1<<0;
sl@0
   185
	$ETimestampPresent	= 1<<1;
sl@0
   186
	$ETimestamp2Present	= 1<<2;
sl@0
   187
	$EContextIdPresent	= 1<<3;
sl@0
   188
	$EPcPresent			= 1<<4;
sl@0
   189
	$EExtraPresent		= 1<<5;
sl@0
   190
	$ERecordTruncated	= 1<<6;
sl@0
   191
	$EMissingRecord		= 1<<7;
sl@0
   192
	
sl@0
   193
	# enum TFlags2 from e32btrace.h
sl@0
   194
	$EMultipartFlagMask	= 3<<0;
sl@0
   195
	$ECpuIdMask			= 0xfff<<20;
sl@0
   196
sl@0
   197
	# enum TMultiPart from e32btrace.h
sl@0
   198
	$EMultipartFirst	= 1;
sl@0
   199
	$EMultipartMiddle	= 2;
sl@0
   200
	$EMultipartLast		= 3;
sl@0
   201
	
sl@0
   202
	$EMaxBTraceDataArray = 80;
sl@0
   203
	
sl@0
   204
	# enum TCategory from e32btrace.h
sl@0
   205
	$EThreadIdentification = 3;
sl@0
   206
	
sl@0
   207
	# enum TThreadIdentification from e32btrace.h
sl@0
   208
	$EThreadCreate = 2;
sl@0
   209
	$EThreadName = 4;
sl@0
   210
	$EProcessName = 5;
sl@0
   211
	$EThreadId = 6;
sl@0
   212
	
sl@0
   213
	# Context Id bits from e32btrace.h
sl@0
   214
	$EContextIdMask = 0x00000003;
sl@0
   215
	$EContextIdThread = 0;
sl@0
   216
	$EContextIdFIQ = 0x1;
sl@0
   217
	$EContextIdIRQ = 0x2;
sl@0
   218
	$EContextIdIDFC = 0x3;
sl@0
   219
sl@0
   220
	# enum TClassificationRange from e32btraceu.h
sl@0
   221
	$EAllRangeFirst = 192;
sl@0
   222
	$EAllRangeLast = 222;
sl@0
   223
sl@0
   224
	%TCategoryIdToString = 
sl@0
   225
		(
sl@0
   226
		0 => "ERDebugPrintf",
sl@0
   227
		1 => "EKernPrintf",
sl@0
   228
		2 => "EPlatsecPrintf",
sl@0
   229
		3 => "EThreadIdentification",
sl@0
   230
		4 => "ECpuUsage",
sl@0
   231
        5 => "EKernPerfLog",
sl@0
   232
        6 => "EClientServer",
sl@0
   233
        7 => "ERequests",
sl@0
   234
        8 => "EChunks",
sl@0
   235
        9 => "ECodeSegs",
sl@0
   236
		10 => "EPaging",
sl@0
   237
		11 => "EThreadPriority",
sl@0
   238
		12 => "EPagingMedia",
sl@0
   239
		13 => "EKernelMemory",
sl@0
   240
		14 => "EHeap",
sl@0
   241
		15 => "EMetaTrace",
sl@0
   242
		16 => "ERamAllocator",
sl@0
   243
		17 => "EFastMutex",
sl@0
   244
		18 => "EProfiling", 
sl@0
   245
        19 => "EResourceManager",
sl@0
   246
        20 => "EResourceManagerUs",
sl@0
   247
		21 => "ERawEvent ",
sl@0
   248
		128 => "EPlatformSpecificFirst",
sl@0
   249
		191 => "EPlatformSpecificLast",
sl@0
   250
		192 => "ESymbianExtentionsFirst",
sl@0
   251
sl@0
   252
		# UTrace "ALL" range 
sl@0
   253
		192 => "EPanic",
sl@0
   254
		193 => "EError",
sl@0
   255
		194 => "EWarning", 
sl@0
   256
		195 => "EBorder", 
sl@0
   257
		196 => "EState", 
sl@0
   258
		197 => "EInternals", 
sl@0
   259
		198 => "EDump", 
sl@0
   260
		199 => "EFlow", 
sl@0
   261
		200 => "ESystemCharacteristicMetrics", 
sl@0
   262
		201 => "EAdhoc",
sl@0
   263
sl@0
   264
		253 => "ESymbianExtentionsLast",
sl@0
   265
		254 => "ETest1",
sl@0
   266
		255 => "ETest2",
sl@0
   267
		);
sl@0
   268
sl@0
   269
sl@0
   270
	%ProcessNames;
sl@0
   271
	%ThreadNames;
sl@0
   272
	%ThreadIds;
sl@0
   273
	
sl@0
   274
	
sl@0
   275
	# print column titles
sl@0
   276
	if ($PrintFlagFilePos) {printf "FilePos, ";}	# col #0
sl@0
   277
	if ($PrintFlagHdrLen) {	printf "Len, ";}		# col #1
sl@0
   278
	if ($PrintFlagHdrFlags) {printf "Flags, "; }	# col #2
sl@0
   279
	printf "Category, ";			# col #3
sl@0
   280
	printf "TimeStamp, ";			# col #4
sl@0
   281
	printf "Delta, ";				# col #5
sl@0
   282
	printf "context Id, ";			# col #6
sl@0
   283
	printf "PC, ";					# col #7
sl@0
   284
	printf "UID, ";					# col #8
sl@0
   285
	if ($PrintFlagFormatString){printf "Format string, ";}	# col #9
sl@0
   286
	printf "Formatted text, ";		# col #10
sl@0
   287
	print "\n\n";
sl@0
   288
sl@0
   289
	
sl@0
   290
	while (1)
sl@0
   291
		{
sl@0
   292
		my $pos = tell (LOGFILE);
sl@0
   293
		
sl@0
   294
		# print file pos (col #0)
sl@0
   295
		if ($PrintFlagFilePos){	printf ("0x%08X, ", $pos);}
sl@0
   296
		
sl@0
   297
		my $category;
sl@0
   298
		my $subCategory;
sl@0
   299
		my $multipartFlags = 0;
sl@0
   300
		my $recordData = "";
sl@0
   301
		my $recordLen;
sl@0
   302
		my $recordPos = 0;
sl@0
   303
		
sl@0
   304
		$recordLen = ReadRecord(LOGFILE, \$pos, \$recordData, \$category, \$subCategory, \$multipartFlags, $RawMode);
sl@0
   305
		if ($recordLen == -1)
sl@0
   306
			{last;}
sl@0
   307
sl@0
   308
			
sl@0
   309
		if (!$RawMode && ($multipartFlags == $EMultipartMiddle || $multipartFlags == $EMultipartLast))
sl@0
   310
			{next;}
sl@0
   311
					
sl@0
   312
#		print record contents
sl@0
   313
#		my $buf;
sl@0
   314
#					for (my $i=0; $i < $recordLen; $i+=4)
sl@0
   315
#						{
sl@0
   316
#		$buf.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos+$i, 4)));
sl@0
   317
#						}
sl@0
   318
#		printf "\n[$buf\n]";				
sl@0
   319
sl@0
   320
sl@0
   321
		# for UTrace "ALL" range, read UID 
sl@0
   322
		if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast && 
sl@0
   323
			(!$RawMode) && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
sl@0
   324
			{
sl@0
   325
			$uid = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   326
			$recordPos+= 4;	
sl@0
   327
sl@0
   328
			# then read formatID			
sl@0
   329
			$FormatIdIsSubCategory = ($subCategory != 0) ? 1 : 0;
sl@0
   330
			if ($FormatIdIsSubCategory)
sl@0
   331
				{
sl@0
   332
				$formatId = $subCategory
sl@0
   333
				}
sl@0
   334
			else				
sl@0
   335
				{
sl@0
   336
				$formatId = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   337
  				$recordPos+= 4;
sl@0
   338
				}
sl@0
   339
			}
sl@0
   340
		
sl@0
   341
					
sl@0
   342
		# print UID (col #8)
sl@0
   343
		printf "0x%08X, ", $uid;
sl@0
   344
sl@0
   345
			
sl@0
   346
		my $formatTable;
sl@0
   347
		my $formatString;
sl@0
   348
		if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast)
sl@0
   349
			{
sl@0
   350
			$formatString = $FormatTables{$uid}{$formatId};
sl@0
   351
			}
sl@0
   352
		else
sl@0
   353
			{
sl@0
   354
			$formatString = $FormatTables{$category}{$subCategory};
sl@0
   355
			}
sl@0
   356
sl@0
   357
sl@0
   358
		# Get thread names
sl@0
   359
		if ($category == $EThreadIdentification)
sl@0
   360
			{
sl@0
   361
			if ($subCategory == $EProcessName)
sl@0
   362
				{
sl@0
   363
				my $process = unpack("V", substr($recordData, 4, 4));
sl@0
   364
				my $processName = substr($recordData, 8, $recordLen - 8);	
sl@0
   365
#				printf ("\nprocess [%08X] processName [$processName]\n", $process);
sl@0
   366
				$ProcessNames{$process} = $processName;
sl@0
   367
				}
sl@0
   368
			elsif ($subCategory == $EThreadCreate || $subCategory == $EThreadName)
sl@0
   369
				{
sl@0
   370
				my $thread = unpack("V", substr($recordData, 0, 4));
sl@0
   371
				my $process = unpack("V", substr($recordData, 4, 4));
sl@0
   372
				my $threadName = substr($recordData, 8, $recordLen - 8);	
sl@0
   373
#				printf ("\nprocess [%08X] thread [%08X] threadName [$threadName]\n", $process, $thread, $threadName);
sl@0
   374
				$ThreadNames{$thread} = $ProcessNames{$process} . "::" . $threadName;
sl@0
   375
				}
sl@0
   376
			elsif ($subCategory == $EThreadId)
sl@0
   377
				{
sl@0
   378
				my $thread = unpack("V", substr($recordData, 0, 4));
sl@0
   379
				my $process = unpack("V", substr($recordData, 4, 4));
sl@0
   380
				my $threadId = unpack("V", substr($recordData, 8, 4));
sl@0
   381
#				printf ("\nprocess [%08X] thread [%08X] threadId [%08X]\n", $process, $thread, $threadId);
sl@0
   382
				$ThreadIds{$thread} = $threadId;
sl@0
   383
				}
sl@0
   384
			}
sl@0
   385
			
sl@0
   386
			
sl@0
   387
		# print Format string (col #9)
sl@0
   388
		if ($PrintFlagFormatString)
sl@0
   389
			{
sl@0
   390
			my $formatStringWithoutCommas = $formatString;
sl@0
   391
			$formatStringWithoutCommas=~ s/,/ /g;
sl@0
   392
			printf "%s, ", $formatStringWithoutCommas;
sl@0
   393
			}
sl@0
   394
sl@0
   395
		my $formattedText;
sl@0
   396
		
sl@0
   397
		my $lenFormatString = length($formatString);
sl@0
   398
		if ($lenFormatString && !$RawMode && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
sl@0
   399
			{
sl@0
   400
			for (my $i=0; $i<$lenFormatString; $i++)
sl@0
   401
				{
sl@0
   402
				my $c = (substr ($formatString, $i, 1));
sl@0
   403
#				printf "$c\n";
sl@0
   404
				if ($c eq "%")
sl@0
   405
					{
sl@0
   406
					undef my $fieldLen;
sl@0
   407
					$i++;
sl@0
   408
	        		$c = (substr ($formatString, $i, 1));
sl@0
   409
					if ($c eq "%")
sl@0
   410
						{
sl@0
   411
						$formattedText.= substr ($formatString, $i, 1);
sl@0
   412
						next;
sl@0
   413
						}
sl@0
   414
					if ($c eq "*")	## take length from buffer
sl@0
   415
						{
sl@0
   416
						$fieldLen = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   417
						if ($fieldLen > $recordLen-$recordPos)
sl@0
   418
							{
sl@0
   419
							$formattedText.= "*** Invalid field length ***";
sl@0
   420
							last;
sl@0
   421
							}
sl@0
   422
						$recordPos+= 4;
sl@0
   423
						$i++;
sl@0
   424
		        		$c = (substr ($formatString, $i, 1));
sl@0
   425
						}
sl@0
   426
					if (lc $c eq "x" || $c eq "h")
sl@0
   427
						{
sl@0
   428
						if (defined $fieldLen)
sl@0
   429
							{
sl@0
   430
							if (($fieldLen & 3) == 0)
sl@0
   431
								{
sl@0
   432
								for (my $i=0; $i< $fieldLen; $i+= 4)
sl@0
   433
									{
sl@0
   434
									$formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos, 4)));
sl@0
   435
									$recordPos+= 4;
sl@0
   436
									}
sl@0
   437
								}
sl@0
   438
							else
sl@0
   439
								{
sl@0
   440
								for (my $i=0; $i< $fieldLen; $i++)
sl@0
   441
									{
sl@0
   442
									$formattedText.= sprintf ("%02X ", unpack("C", substr($recordData, $recordPos, 1)));
sl@0
   443
									$recordPos++;
sl@0
   444
									}
sl@0
   445
								}
sl@0
   446
							}
sl@0
   447
						else
sl@0
   448
							{
sl@0
   449
							$formattedText.= sprintf ("0x%08X", unpack("V", substr($recordData, $recordPos, 4)));
sl@0
   450
							$recordPos+= 4;
sl@0
   451
							}
sl@0
   452
						$recordPos = ($recordPos + 3) & ~3;
sl@0
   453
						next;
sl@0
   454
						}
sl@0
   455
					# display "%ld" as hex for now as don't know how to get perl to use or display a 64 decimal value
sl@0
   456
					elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "d")
sl@0
   457
						{
sl@0
   458
						$i++;
sl@0
   459
						my $loWord = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   460
						$recordPos+= 4;
sl@0
   461
						my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   462
						$recordPos+= 4;
sl@0
   463
						$formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
sl@0
   464
						}
sl@0
   465
					elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "x")
sl@0
   466
						{
sl@0
   467
						$i++;
sl@0
   468
						my $loWord = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   469
						$recordPos+= 4;
sl@0
   470
						my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
sl@0
   471
						$recordPos+= 4;
sl@0
   472
						$formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
sl@0
   473
						}
sl@0
   474
					elsif (lc $c eq "d")
sl@0
   475
						{
sl@0
   476
						$formattedText.= sprintf ("%d", unpack("V", substr($recordData, $recordPos, 4)));
sl@0
   477
						$recordPos+= 4;
sl@0
   478
						$recordPos = ($recordPos + 3) & ~3;
sl@0
   479
						next;
sl@0
   480
						}
sl@0
   481
					elsif ($c eq "s")
sl@0
   482
						{
sl@0
   483
						if (!defined $fieldLen) 
sl@0
   484
							{$fieldLen = $recordLen - $recordPos;}
sl@0
   485
						$formattedText.= substr($recordData, $recordPos, $fieldLen);
sl@0
   486
						$recordPos+= $fieldLen; 
sl@0
   487
						$recordPos = ($recordPos + 3) & ~3;
sl@0
   488
						next;
sl@0
   489
						}
sl@0
   490
					elsif ($c eq "S")
sl@0
   491
						{
sl@0
   492
						if (!defined $fieldLen) 
sl@0
   493
							{$fieldLen = $recordLen-$recordPos;}
sl@0
   494
						for (my $j=0; $j < $fieldLen; $j+=2)
sl@0
   495
							{
sl@0
   496
					        my $byte = unpack("c", substr ($recordData, $recordPos+$j, 1));
sl@0
   497
 							$formattedText.= sprintf ("%c", $byte);
sl@0
   498
							}
sl@0
   499
						$recordPos+= $fieldLen; 
sl@0
   500
						$recordPos = ($recordPos + 3) & ~3;
sl@0
   501
						next;
sl@0
   502
						}
sl@0
   503
					elsif ($c eq "c")
sl@0
   504
						{
sl@0
   505
				        my $byte = unpack("c", substr ($recordData, $recordPos, 1));
sl@0
   506
						$formattedText.= sprintf ("%c", $byte);
sl@0
   507
						}
sl@0
   508
					}
sl@0
   509
				else
sl@0
   510
					{
sl@0
   511
					$formattedText.= $c;
sl@0
   512
					}
sl@0
   513
				}
sl@0
   514
			}
sl@0
   515
		else	# no format string : print as hex
sl@0
   516
			{
sl@0
   517
			for (my $i=0; $i < $recordLen; $i+=4)
sl@0
   518
				{
sl@0
   519
				$formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $i, 4)));
sl@0
   520
				}
sl@0
   521
			$recordPos+= $recordLen; $recordLen = 0;
sl@0
   522
			
sl@0
   523
			}
sl@0
   524
		
sl@0
   525
sl@0
   526
		# print Formatted text (col #10)
sl@0
   527
		$formattedText=~ s/,/;/g;
sl@0
   528
		$formattedText=~ s/\r//g;
sl@0
   529
		$formattedText=~ s/\n/,/g;
sl@0
   530
		printf "%s", $formattedText;
sl@0
   531
sl@0
   532
		printf("\n");
sl@0
   533
sl@0
   534
		if ($len < 0 || $recordLen < 0)	{die "truncated file";}
sl@0
   535
  
sl@0
   536
sl@0
   537
		$pos+= ($len +3) & ~3;
sl@0
   538
		seek (LOGFILE, $pos, SEEK_SET) or die "truncated file";
sl@0
   539
		$i++;
sl@0
   540
		}
sl@0
   541
sl@0
   542
	close (LOGFILE);
sl@0
   543
sl@0
   544
	if ($VerboseMode)
sl@0
   545
		{
sl@0
   546
		print "*** Processes ***\n";
sl@0
   547
		for $id ( keys %ProcessNames )
sl@0
   548
			{
sl@0
   549
			printf ("process %08X ProcessName %s\n", $id, $ProcessNames{$id});
sl@0
   550
			}
sl@0
   551
		print "*** Thread ***\n";
sl@0
   552
		for $id ( keys %ThreadNames )
sl@0
   553
			{
sl@0
   554
			printf ("thread %08X ThreadName %s::%X\n", $id, $ThreadNames{$id}, $ThreadIds{$id});
sl@0
   555
			}
sl@0
   556
		}
sl@0
   557
sl@0
   558
    }
sl@0
   559
sl@0
   560
    
sl@0
   561
sub ReadSingleRecord
sl@0
   562
	{
sl@0
   563
	($fh, $data, $dataLen, $recordLen, $category, $subCategory, $multipartFlags, $extraN, $totalLen, $offset, $RawMode) = @_;	
sl@0
   564
	
sl@0
   565
	my $hdr;
sl@0
   566
	my $flags;
sl@0
   567
	my $header2;
sl@0
   568
	my $timestamp;
sl@0
   569
	my $timestamp2;
sl@0
   570
	my $contextId;
sl@0
   571
	my $programConter;	
sl@0
   572
	
sl@0
   573
	my $recordOffset = 0;
sl@0
   574
	
sl@0
   575
	$timestampLast;	
sl@0
   576
	my $timestampDelta = 0;	
sl@0
   577
	
sl@0
   578
	my $bytesRead = read($fh, $hdr, 4);
sl@0
   579
	
sl@0
   580
	
sl@0
   581
	if ($bytesRead < 4)	
sl@0
   582
		{return -1;}
sl@0
   583
sl@0
   584
	($$recordLen,$flags,$$category,$$subCategory) = unpack("CCCC", $hdr);
sl@0
   585
	$$dataLen = $$recordLen-4;
sl@0
   586
	
sl@0
   587
	if ($flags & $EHeader2Present)
sl@0
   588
		{$$multipartFlags = (ReadDword($fh) & $EMultipartFlagMask); $$dataLen-= 4}
sl@0
   589
	else
sl@0
   590
		{$$multipartFlags = 0;}
sl@0
   591
	if ($flags & $ETimestampPresent)
sl@0
   592
		{$timestamp = ReadDword($fh); $$dataLen-= 4;}
sl@0
   593
	if ($flags & $ETimestamp2Present)
sl@0
   594
		{$timestamp2 = ReadDword($fh); $$dataLen-= 4;}
sl@0
   595
	if ($flags & $EContextIdPresent)
sl@0
   596
		{$contextId = ReadDword($fh); $$dataLen-= 4;}
sl@0
   597
	if ($flags & $EPcPresent)
sl@0
   598
		{$programConter = ReadDword($fh); $$dataLen-= 4;}
sl@0
   599
	if ($flags & $EExtraPresent)
sl@0
   600
		{$$extraN = ReadDword($fh); $$dataLen-= 4;}
sl@0
   601
	if ($$multipartFlags != 0)
sl@0
   602
		{
sl@0
   603
		$$totalLen = ReadDword($fh);  $$dataLen-= 4;
sl@0
   604
		if ($$multipartFlags == $EMultipartMiddle || $$multipartFlags == $EMultipartLast)
sl@0
   605
			{$$offset = ReadDword($fh);  $$totalLen-= 4; $$dataLen-= 4;}
sl@0
   606
		}				
sl@0
   607
sl@0
   608
	$timestampDelta = $timestamp - $timestampLast;
sl@0
   609
	$timestampLast = $timestamp;
sl@0
   610
sl@0
   611
	read($fh, $$data, ($$dataLen + 3) & ~3);
sl@0
   612
sl@0
   613
sl@0
   614
	if ($RawMode || $$multipartFlags == $EMultipartFirst || $$multipartFlags == 0)
sl@0
   615
		{
sl@0
   616
		# print header len (col #1)
sl@0
   617
		if ($PrintFlagHdrLen){printf ("0x%02X, ", $$recordLen);}
sl@0
   618
	
sl@0
   619
		# print header flags (col #2)
sl@0
   620
		if ($PrintFlagHdrFlags)
sl@0
   621
			{
sl@0
   622
			printf ("%02X ", $flags);
sl@0
   623
			if ($flags & $EHeader2Present) {printf "EHeader2Present ";}
sl@0
   624
			if ($flags & $ETimestampPresent) {printf "ETimestampPresent ";}
sl@0
   625
			if ($flags & $ETimestamp2Present) {printf "ETimestamp2Present ";}
sl@0
   626
			if ($flags & $EContextIdPresent) {printf "EContextIdPresent ";}
sl@0
   627
			if ($flags & $EPcPresent) {printf "EPcPresent ";}
sl@0
   628
			if ($$multipartFlags != 0)
sl@0
   629
				{
sl@0
   630
				printf "EExtraPresent ";
sl@0
   631
				if ($$multipartFlags == $EMultipartFirst) {print "EMultipartFirst ";}
sl@0
   632
				elsif ($$multipartFlags == $EMultipartMiddle) {print "EMultipartMiddle ";}
sl@0
   633
				elsif ($$multipartFlags == $EMultipartLast) {print "EMultipartLast ";}
sl@0
   634
				printf ("ExtraN(0x%08X) ", $$extraN);
sl@0
   635
				}
sl@0
   636
			if ($flags & $ERecordTruncated) {printf "ERecordTruncated ";}
sl@0
   637
			if ($flags & $EMissingRecord) {printf "EMissingRecord ";}
sl@0
   638
			print ",";
sl@0
   639
			}
sl@0
   640
				
sl@0
   641
		# print category (col #3)
sl@0
   642
		printf "(%d;%d) $categoryString  , ", $$category, $$subCategory;
sl@0
   643
	
sl@0
   644
		# print timestamp(s) (col #4)
sl@0
   645
		printf "0x";
sl@0
   646
		if (defined $timestamp2) {printf "%08X : ", $timestamp2;}
sl@0
   647
		printf "%08X", $timestamp;
sl@0
   648
		printf ", ";;
sl@0
   649
	
sl@0
   650
		# print timestamp delta (col #5)
sl@0
   651
		printf "0x%08X, ", $timestampDelta;
sl@0
   652
sl@0
   653
		# print context Id (col #6)
sl@0
   654
		if (!$RawMode && defined $ThreadNames{$contextId})
sl@0
   655
			{
sl@0
   656
			printf ("%s::%X, ", $ThreadNames{$contextId}, $ThreadIds{$contextId});
sl@0
   657
			}
sl@0
   658
		else			
sl@0
   659
			{
sl@0
   660
			if ((($contextId & $EContextIdMask) == $EContextIdThread) || $RawMode)
sl@0
   661
				{printf "0x%08X, ", $contextId;}
sl@0
   662
			elsif (($contextId & $EContextIdMask) == $EContextIdFIQ)
sl@0
   663
				{printf "FIQ, ";}
sl@0
   664
			elsif (($contextId & $EContextIdMask) == $EContextIdIRQ)
sl@0
   665
				{printf "IRQ, ";}
sl@0
   666
			elsif (($contextId & $EContextIdMask) == $EContextIdIDFC)
sl@0
   667
				{printf "IDFC, ";}
sl@0
   668
			}
sl@0
   669
	
sl@0
   670
		# print Program Counter (col #7)
sl@0
   671
		printf "0x%08X, ", $programConter;
sl@0
   672
		}
sl@0
   673
sl@0
   674
		
sl@0
   675
	
sl@0
   676
	
sl@0
   677
#########################################################
sl@0
   678
#	my $hex;
sl@0
   679
#	for (my $i=0; $i < $$dataLen; $i+=4)
sl@0
   680
#		{
sl@0
   681
#		$hex.= sprintf ("%08X ", unpack("V", substr($$data, $i, 4)));
sl@0
   682
#		}
sl@0
   683
#	printf "\nadding [$hex]\n";
sl@0
   684
#########################################################
sl@0
   685
	return $bytesRead
sl@0
   686
	}
sl@0
   687
sl@0
   688
	      
sl@0
   689
sub ReadRecord 
sl@0
   690
	{
sl@0
   691
	($fh, $recordPos, $recordData, $category, $subCategory, $multipartFlags, $RawMode) = @_;
sl@0
   692
#	printf "CurrentPos %08X\n", $pos;
sl@0
   693
sl@0
   694
sl@0
   695
sl@0
   696
	seek ($fh, $$recordPos, SEEK_SET) or die "truncated file";
sl@0
   697
	my $recordLen;
sl@0
   698
	my $extraN;
sl@0
   699
	my $totalLen;
sl@0
   700
	my $offset;
sl@0
   701
	my $dataLen;
sl@0
   702
	my $data;
sl@0
   703
	my $bytesRead;
sl@0
   704
	
sl@0
   705
	
sl@0
   706
	$bytesRead = ReadSingleRecord($fh,  \$data, \$dataLen, \$recordLen, \$$category, \$$subCategory, \$$multipartFlags, \$extraN, \$totalLen, \$offset, $RawMode);
sl@0
   707
sl@0
   708
	if ($bytesRead == -1)	# eof ?
sl@0
   709
		{return -1; }
sl@0
   710
	$$recordPos+= ($recordLen +3) & ~3;
sl@0
   711
	
sl@0
   712
	$$recordData = $data;
sl@0
   713
    $offset = $dataLen;
sl@0
   714
sl@0
   715
	$offset-= 4;		# subtract 4 bytes for UID ?????????
sl@0
   716
    
sl@0
   717
    if ($RawMode || $$multipartFlags != $EMultipartFirst)
sl@0
   718
    	{return $dataLen;}
sl@0
   719
sl@0
   720
    $pos = $$recordPos;
sl@0
   721
sl@0
   722
	while (1)
sl@0
   723
		{
sl@0
   724
		
sl@0
   725
		# find next record, i.e. look for a record which matches $extraN 
sl@0
   726
		
sl@0
   727
		seek ($fh, $pos, SEEK_SET) or die "truncated file";
sl@0
   728
sl@0
   729
		my $recordLen;
sl@0
   730
		
sl@0
   731
		my $category;
sl@0
   732
		my $subCategory;
sl@0
   733
		my $multipartFlags;
sl@0
   734
		my $currentExtraN;
sl@0
   735
		my $currentOffset;
sl@0
   736
		
sl@0
   737
		my $totalLen;
sl@0
   738
		my $currentDataLen;
sl@0
   739
		my $data;
sl@0
   740
		$bytesRead = ReadSingleRecord($fh, \$data, \$currentDataLen, \$recordLen, \$category, \$subCategory, \$multipartFlags, \$currentExtraN, \$totalLen, \$currentOffset, $RawMode);
sl@0
   741
		if ($bytesRead == -1)	# eof ?
sl@0
   742
			{return -1; }
sl@0
   743
		$pos+= ($recordLen +3) & ~3;
sl@0
   744
		
sl@0
   745
#		printf "\npos %08X, Seaching for (extra %08X, offset %08X), found (extra %08X, offset %08X)\n",
sl@0
   746
#			$pos, $extraN, $offset, $currentExtraN, $currentOffset;
sl@0
   747
sl@0
   748
		if ($currentExtraN == $extraN && $currentOffset == $offset)
sl@0
   749
			{
sl@0
   750
			$$recordData.= $data;
sl@0
   751
			$offset+= $currentDataLen;
sl@0
   752
			$dataLen+= $currentDataLen;
sl@0
   753
			}
sl@0
   754
			
sl@0
   755
		if ($multipartFlags == $EMultipartLast)
sl@0
   756
			{last;}
sl@0
   757
		}
sl@0
   758
	
sl@0
   759
	return $dataLen;
sl@0
   760
	}	
sl@0
   761
sl@0
   762
sub ReadDword {
sl@0
   763
	(my $fh) = @_;
sl@0
   764
	my $buffer;
sl@0
   765
sl@0
   766
	$bytesRead = read($fh, $buffer, 4);
sl@0
   767
	if ($bytesRead < 4) 	{die "truncated file";}
sl@0
   768
sl@0
   769
	my $dword = unpack("V", $buffer);
sl@0
   770
sl@0
   771
	return $dword
sl@0
   772
	};
sl@0
   773
sl@0
   774
sub ReadByte {
sl@0
   775
	(my $fh) = @_;
sl@0
   776
	my $buffer;
sl@0
   777
sl@0
   778
	$bytesRead = read($fh, $buffer, 1);
sl@0
   779
	if ($bytesRead < 1) 	{die "truncated file";}
sl@0
   780
sl@0
   781
	my $byte = unpack("C", $buffer);
sl@0
   782
sl@0
   783
	return $byte
sl@0
   784
	};
sl@0
   785
sl@0
   786
    
sl@0
   787
	
sl@0
   788
sub PrintFormatTables($)
sl@0
   789
	{
sl@0
   790
	my ($formatTables) = @_;
sl@0
   791
		
sl@0
   792
	for $tableIndex ( sort keys %$formatTables )
sl@0
   793
		{
sl@0
   794
		printf ("SYMTraceFormatCategory %08X:\n", $tableIndex);
sl@0
   795
		for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
sl@0
   796
			{
sl@0
   797
			printf ("%08X => %s\n", $formatId, $$formatTables{$tableIndex}{$formatId});
sl@0
   798
			}
sl@0
   799
			print "\n";
sl@0
   800
		}
sl@0
   801
	}
sl@0
   802
        
sl@0
   803
sl@0
   804
sl@0
   805
sub OutputSawDictionary($)
sl@0
   806
	{
sl@0
   807
	my ($formatTables) = @_;
sl@0
   808
sl@0
   809
sl@0
   810
	# SAW enums
sl@0
   811
	$EFieldTypeHexDump = 0;
sl@0
   812
	$EFieldTypeHex = 1;
sl@0
   813
	$EFieldTypeDecimal = 2;
sl@0
   814
	$EFieldTypeStringToEnd = 3;
sl@0
   815
	$EFieldTypeNullTerminatedString = 4;
sl@0
   816
	$EFieldTypeHexDumpToEnd = 5;
sl@0
   817
	$EFieldTypeUnicodeToEnd = 6;
sl@0
   818
	$EFieldTypeNullTerminatedUnicode = 7;
sl@0
   819
	$EFieldTypeCountedUnicode = 8;
sl@0
   820
	$EFieldTypeCountedHexDump = 9;
sl@0
   821
	$EFieldTypeCountedString = 10;
sl@0
   822
sl@0
   823
	my $moduleIds;	# string containg all UIDs separared by semi-colons
sl@0
   824
		
sl@0
   825
	for $tableIndex ( sort keys %$formatTables )
sl@0
   826
		{
sl@0
   827
		if ($tableIndex < 256)
sl@0
   828
			{
sl@0
   829
			next;
sl@0
   830
			}
sl@0
   831
		$moduleIds.= sprintf ("%08X;", $tableIndex);
sl@0
   832
		
sl@0
   833
		printf ("MODULEID_%08X_DESC=\n", $tableIndex);
sl@0
   834
		printf ("MODULEID_%08X_NAME=%08X\n", $tableIndex, $tableIndex);
sl@0
   835
		
sl@0
   836
		my $formatIds;
sl@0
   837
		$formatIds = sprintf ("MODULEID_%08X_FORMATIDS=", $tableIndex);
sl@0
   838
		
sl@0
   839
		for $formatId  (sort keys %{ $$formatTables{$tableIndex} } )
sl@0
   840
			{
sl@0
   841
			$formatIds.= sprintf ("%d;", $formatId);
sl@0
   842
			}
sl@0
   843
		printf ("$formatIds\n");
sl@0
   844
		
sl@0
   845
		
sl@0
   846
		for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
sl@0
   847
			{
sl@0
   848
			my $fieldCount = 0;
sl@0
   849
			my $formatString = $$formatTables{$tableIndex}{$formatId};
sl@0
   850
			
sl@0
   851
#printf ("formatString = (%s)\n", $formatString);
sl@0
   852
sl@0
   853
			# format name is the first format string up until the first space or '%' character or end-of line ...
sl@0
   854
			$formatString=~ m/^[^%\s]*/;
sl@0
   855
			my $formatName = $&;
sl@0
   856
			
sl@0
   857
			# thow the format name away
sl@0
   858
			$formatString = $';
sl@0
   859
			
sl@0
   860
			# strip the leading space
sl@0
   861
			$formatString=~ s/\s*//;
sl@0
   862
sl@0
   863
			printf ("MODULEID_%08X_FORMATID_%d_NAME=%s\n", $tableIndex, $formatId, $formatName);
sl@0
   864
#printf ("MODULEID_%08X_FORMATID_%d_DESC=\n", $tableIndex, $formatId);
sl@0
   865
sl@0
   866
			my $lenFormatString = length($formatString);
sl@0
   867
			
sl@0
   868
			my $formattedText;
sl@0
   869
			my $fieldType = $EFieldTypeHex;
sl@0
   870
			my $fieldLen = 0;
sl@0
   871
			while (length($formatString))
sl@0
   872
				{
sl@0
   873
				my $c = (substr ($formatString, 0, 1));
sl@0
   874
#print ("[$formatString][$c]\n");				
sl@0
   875
				$formatString=~ s/.//;	# strip the leading space
sl@0
   876
				if ($c eq "%")
sl@0
   877
					{
sl@0
   878
#print "found %\n";							
sl@0
   879
					my $fieldLenSpecified = 0;
sl@0
   880
	        		$c = (substr ($formatString, 0, 1));
sl@0
   881
					$formatString=~ s/.//;	# discard char
sl@0
   882
#print "c2=$c\n";							
sl@0
   883
					if ($c eq "%")
sl@0
   884
						{
sl@0
   885
						$formattedText.= substr ($formatString, 0, 1);
sl@0
   886
						next;
sl@0
   887
						}
sl@0
   888
					if ($c eq "*")	## take length from buffer
sl@0
   889
						{
sl@0
   890
						$fieldLenSpecified = 1;
sl@0
   891
		        		$c = (substr ($formatString, 0, 1));
sl@0
   892
						$formatString=~ s/.//;	# discard char
sl@0
   893
						}
sl@0
   894
					if (lc $c eq "x" || $c eq "h")
sl@0
   895
						{
sl@0
   896
						## deal wilth $fieldLenSpecified
sl@0
   897
						if ($fieldLenSpecified)
sl@0
   898
							{
sl@0
   899
							$fieldType = $EFieldTypeCountedHexDump;
sl@0
   900
							$fieldLen = 0;
sl@0
   901
							}
sl@0
   902
						else
sl@0
   903
							{
sl@0
   904
							$fieldType = $EFieldTypeHex;
sl@0
   905
							$fieldLen = 4;
sl@0
   906
							}
sl@0
   907
						}
sl@0
   908
					elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "d")
sl@0
   909
						{
sl@0
   910
						$formatString=~ s/.//;	# discard char
sl@0
   911
						$fieldType = $EFieldTypeDecimal;
sl@0
   912
						$fieldLen = 8;
sl@0
   913
						}
sl@0
   914
					elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "x")
sl@0
   915
						{
sl@0
   916
						$formatString=~ s/.//;	# discard char
sl@0
   917
						$fieldType = $EFieldTypeHex;
sl@0
   918
						$fieldLen = 8;
sl@0
   919
						}
sl@0
   920
					elsif (lc $c eq "d")
sl@0
   921
						{
sl@0
   922
						$fieldType = $EFieldTypeDecimal;
sl@0
   923
						$fieldLen = 4;
sl@0
   924
						}
sl@0
   925
					elsif ($c eq "s")
sl@0
   926
						{
sl@0
   927
						## deal wilth $fieldLenSpecified
sl@0
   928
						if ($fieldLenSpecified)
sl@0
   929
							{
sl@0
   930
							$fieldType = $EFieldTypeCountedString;
sl@0
   931
							$fieldLen = 0;
sl@0
   932
							}
sl@0
   933
						else
sl@0
   934
							{
sl@0
   935
							$fieldType = $EFieldTypeStringToEnd;
sl@0
   936
							$fieldLen = 0;
sl@0
   937
							}
sl@0
   938
						}
sl@0
   939
					elsif ($c eq "S")
sl@0
   940
						{
sl@0
   941
						## deal wilth $fieldLenSpecified
sl@0
   942
						if ($fieldLenSpecified)
sl@0
   943
							{
sl@0
   944
							$fieldType = $EFieldTypeCountedUnicode;
sl@0
   945
							$fieldLen = 0;
sl@0
   946
							}
sl@0
   947
						else
sl@0
   948
							{
sl@0
   949
							$fieldType = EFieldTypeUnicodeToEnd;
sl@0
   950
							$fieldLen = 0;
sl@0
   951
							}
sl@0
   952
						}
sl@0
   953
					elsif ($c eq "c")
sl@0
   954
						{
sl@0
   955
						$fieldType = $EFieldTypeHex;
sl@0
   956
						$fieldLen = 1;
sl@0
   957
						}
sl@0
   958
					printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_NAME=%s\n", $tableIndex, $formatId, $fieldCount, $formattedText);
sl@0
   959
					printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_TYPE=%s\n", $tableIndex, $formatId, $fieldCount, $fieldType);
sl@0
   960
					if ($fieldLen > 0)
sl@0
   961
						{printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_LENGTH=%s\n", $tableIndex, $formatId, $fieldCount, $fieldLen);}
sl@0
   962
					$fieldCount++;
sl@0
   963
					$formattedText="";
sl@0
   964
					
sl@0
   965
					$formatString=~ s/\s//;	# strip the leading space
sl@0
   966
					}
sl@0
   967
				else
sl@0
   968
					{
sl@0
   969
#					if ($c eq ":") {$formattedText.= '\\'; }
sl@0
   970
					$formattedText.= $c;
sl@0
   971
					}
sl@0
   972
				}
sl@0
   973
			printf ("MODULEID_%08X_FORMATID_%d_FIELDS=%d\n", $tableIndex, $formatId, $fieldCount);
sl@0
   974
			
sl@0
   975
			}
sl@0
   976
		print "MODULEIDS=$moduleIds\n";
sl@0
   977
		}
sl@0
   978
	}
sl@0
   979
	
sl@0
   980
	
sl@0
   981
	
sl@0
   982
	
sl@0
   983
	
sl@0
   984
	
sl@0
   985
	        
sl@0
   986
        
sl@0
   987
sub H2Trace($$)
sl@0
   988
{
sl@0
   989
	%basictypes = (
sl@0
   990
		TInt8		=>	1,
sl@0
   991
		TUint8		=>	1,
sl@0
   992
		TInt16		=>	2,
sl@0
   993
		TUint16		=>	2,
sl@0
   994
		TInt32		=>	4,
sl@0
   995
		TUint32		=>	4,
sl@0
   996
		TInt		=>	4,
sl@0
   997
		TUint		=>	4,
sl@0
   998
		TBool		=>	4,
sl@0
   999
		TInt64		=>	8,
sl@0
  1000
		TUint64		=>	8,
sl@0
  1001
		TLinAddr	=>	4,
sl@0
  1002
		TVersion	=>	4,
sl@0
  1003
		TPde		=>	4,
sl@0
  1004
		TPte		=>	4,
sl@0
  1005
		TProcessPriority => 4,
sl@0
  1006
		TFormatId	=>  2,
sl@0
  1007
	);
sl@0
  1008
	
sl@0
  1009
	if (scalar(@_)!= 2) {
sl@0
  1010
		die "perl h2trace.pl <input.h>\n";
sl@0
  1011
	}
sl@0
  1012
	my ($infile, $filescope) = @_;
sl@0
  1013
	
sl@0
  1014
	if ($VerboseMode)
sl@0
  1015
		{print "\nOpening $infile\n";}
sl@0
  1016
	
sl@0
  1017
	open IN, $infile or die "Can't open $infile for input\n";
sl@0
  1018
	my $in;
sl@0
  1019
	while (<IN>) {
sl@0
  1020
		$in.=$_;
sl@0
  1021
	}
sl@0
  1022
	close IN;
sl@0
  1023
	
sl@0
  1024
	# First remove any backslash-newline combinations
sl@0
  1025
	$in =~ s/\\\n//gms;
sl@0
  1026
	
sl@0
  1027
	# Remove any character constants
sl@0
  1028
	$in =~  s/\'(.?(${0})*?)\'//gms;
sl@0
  1029
	
sl@0
  1030
	# Strip comments beginning with //
sl@0
  1031
	$in =~ s/\/\/(.*?)\n/\n/gms;    #//(.*?)\n
sl@0
  1032
	
sl@0
  1033
	# Strip comments (/* */) but leave doxygen comments (/** */)
sl@0
  1034
	$in =~ s/\/\*[^*](.*?)\*\//\n/gms;  #/*(.*?)*/
sl@0
  1035
	
sl@0
  1036
	
sl@0
  1037
	# Collapse whitespace into a single space or newline
sl@0
  1038
	$in =~ s/\t/\ /gms;
sl@0
  1039
	$in =~ s/\r/\ /gms;
sl@0
  1040
	
sl@0
  1041
	# Tokenize on non-identifier characters
sl@0
  1042
	my @tokens0 = split(/(\W)/,$in);
sl@0
  1043
	my @tokens;
sl@0
  1044
	my $inString = 0;
sl@0
  1045
	my $inComment = 0;
sl@0
  1046
	my $string;
sl@0
  1047
	foreach $t (@tokens0) {
sl@0
  1048
		next if ($t eq "");
sl@0
  1049
		next if (!$inString && ($t eq " " or $t eq ""));
sl@0
  1050
		if ($inComment == 0) 
sl@0
  1051
			{
sl@0
  1052
			if ($t eq "/")
sl@0
  1053
				{$inComment = 1;}
sl@0
  1054
			}
sl@0
  1055
		elsif ($inComment == 1) 
sl@0
  1056
			{
sl@0
  1057
			if ($t eq "*")
sl@0
  1058
				{$inComment = 2;}
sl@0
  1059
			else
sl@0
  1060
				{$inComment = 0;}
sl@0
  1061
			}
sl@0
  1062
		elsif ($inComment == 2) 
sl@0
  1063
			{
sl@0
  1064
			if ($t eq "*")
sl@0
  1065
				{$inComment = 3;}
sl@0
  1066
			}
sl@0
  1067
		elsif ($inComment == 3) 
sl@0
  1068
			{
sl@0
  1069
			if ($t eq "/")
sl@0
  1070
				{
sl@0
  1071
				$inComment = 0;
sl@0
  1072
		        # if we were in a string, need to push previous '*'
sl@0
  1073
		        if ($inString)
sl@0
  1074
		          {
sl@0
  1075
		          push @tokens, "*";
sl@0
  1076
		          }
sl@0
  1077
				$inString = 0;	# end of comment aborts a string
sl@0
  1078
				$string = "";
sl@0
  1079
				}
sl@0
  1080
			else
sl@0
  1081
				{$inComment = 2;}
sl@0
  1082
			}
sl@0
  1083
			
sl@0
  1084
		if ($t eq "\"")
sl@0
  1085
			{
sl@0
  1086
			if (!$inString) 
sl@0
  1087
				{
sl@0
  1088
				$inString=1;
sl@0
  1089
				next;
sl@0
  1090
				}
sl@0
  1091
			else
sl@0
  1092
				{
sl@0
  1093
				$inString=0;
sl@0
  1094
				$t = $string;
sl@0
  1095
				$string = "";
sl@0
  1096
#				if ($VerboseMode) {print "string : [$t]\n";	}
sl@0
  1097
				}
sl@0
  1098
			}
sl@0
  1099
			
sl@0
  1100
		if ($inString)
sl@0
  1101
			{
sl@0
  1102
			$string.= $t;
sl@0
  1103
			next;
sl@0
  1104
			}
sl@0
  1105
		push @tokens, $t;
sl@0
  1106
	}
sl@0
  1107
	
sl@0
  1108
	my $CurrentTraceFormatString;
sl@0
  1109
	my $CurrentTraceFormatCategory;
sl@0
  1110
	# format Key as specified by the @TraceFormatCategory tag is either the current category 
sl@0
  1111
	# or the current UID
sl@0
  1112
	my $CurrentFormatTableKey;	
sl@0
  1113
	
sl@0
  1114
	
sl@0
  1115
	my $line=1;
sl@0
  1116
	parse_scope($filescope, \@tokens, \$line);
sl@0
  1117
sl@0
  1118
	#print $in;
sl@0
  1119
	#print join (" ", @tokens);
sl@0
  1120
}	# end of     H2Trace
sl@0
  1121
	
sl@0
  1122
sl@0
  1123
sl@0
  1124
	sub parse_scope($$$) {
sl@0
  1125
		my ($scope, $tokens, $line) = @_;
sl@0
  1126
		my $state = 1;
sl@0
  1127
		
sl@0
  1128
		my @classes;
sl@0
  1129
		my $curr_offset=0;
sl@0
  1130
		my $overall_align=0;
sl@0
  1131
#		print ">parse_scope $scope->{name}\n";
sl@0
  1132
		
sl@0
  1133
		while (scalar(@$tokens))
sl@0
  1134
			{
sl@0
  1135
			my $t = shift @$tokens;
sl@0
  1136
#			printf "t: [$t] [$$line]\n";
sl@0
  1137
	    	if (!defined ($t)) {
sl@0
  1138
	      		printf "undefined !";
sl@0
  1139
	      		next;
sl@0
  1140
	      	}
sl@0
  1141
			if ($state>=-1 and $t eq "\n") {
sl@0
  1142
				++$$line;
sl@0
  1143
				$state=1;
sl@0
  1144
				next;
sl@0
  1145
			} elsif ($state==-1 and $t ne "\n") {
sl@0
  1146
				next;
sl@0
  1147
			} elsif ($state==-2 and $t ne ';') {
sl@0
  1148
				next;
sl@0
  1149
			}
sl@0
  1150
			
sl@0
  1151
			if ($state>0 and $t eq '#') {
sl@0
  1152
				$t = shift @$tokens;
sl@0
  1153
				if ($t eq 'define') {
sl@0
  1154
					my $ident = shift @$tokens;
sl@0
  1155
					my $defn = shift @$tokens;
sl@0
  1156
					if ($defn ne '(') {	# don't do macros with parameters
sl@0
  1157
#					print "MACRO: $ident :== $defn\n";
sl@0
  1158
					$macros{$ident} = $defn;
sl@0
  1159
					}
sl@0
  1160
				}
sl@0
  1161
				$state=-1;	# skip to next line
sl@0
  1162
				next;
sl@0
  1163
			}
sl@0
  1164
			
sl@0
  1165
			
sl@0
  1166
			if (parse_doxygen($scope,$tokens, $line, $t) == 1)
sl@0
  1167
				{next;}
sl@0
  1168
	
sl@0
  1169
			if ($t eq "namespace" ) {
sl@0
  1170
				$state=0;
sl@0
  1171
				my %cl;
sl@0
  1172
				$cl{specifier}=$t;
sl@0
  1173
				$cl{scope}=$scope;
sl@0
  1174
				$cl{values}=$scope->{values};
sl@0
  1175
				$cl{members}=\$scope->{members};
sl@0
  1176
				$cl{typedefs}=\$scope->{typedefs};
sl@0
  1177
				$cl{FormatTables}=$scope->{FormatTables};
sl@0
  1178
				$cl{formatStrings} =$scope->{formatStrings};
sl@0
  1179
				$cl{formatCategories} =$scope->{formatCategories};
sl@0
  1180
				
sl@0
  1181
				my $new_namespace = \%cl;
sl@0
  1182
				my $n = get_token($scope,$tokens,$line);
sl@0
  1183
				if ($n !~ /\w+/) {
sl@0
  1184
					warn "Unnamed $t not supported at line $$line\n";
sl@0
  1185
					return;
sl@0
  1186
				}
sl@0
  1187
				$new_namespace->{name}=$n;
sl@0
  1188
				my @class_match = grep {$_->{name} eq $n} @classes;
sl@0
  1189
				my $exists = scalar(@class_match);
sl@0
  1190
				my $b = get_token($scope,$tokens,$line);
sl@0
  1191
				if ($b eq ':') {
sl@0
  1192
					die "Inheritance not supported at line $$line\n";
sl@0
  1193
				} elsif ($b eq ';') {
sl@0
  1194
					# forward declaration
sl@0
  1195
					push @classes, $new_namespace unless ($exists);
sl@0
  1196
					next;
sl@0
  1197
				} elsif ($b ne '{') {
sl@0
  1198
					warn "Syntax error#1 at line $$line\n";
sl@0
  1199
					return;
sl@0
  1200
				}
sl@0
  1201
				if ($exists) {
sl@0
  1202
					$new_namespace = $class_match[0];
sl@0
  1203
					if ($new_namespace->{complete}) {
sl@0
  1204
						warn "Duplicate definition of $cl{specifier} $n\n";
sl@0
  1205
					}
sl@0
  1206
				}
sl@0
  1207
				push @classes, $new_namespace unless ($exists);
sl@0
  1208
				parse_scope($new_namespace, $tokens, $line);
sl@0
  1209
				next;
sl@0
  1210
			}
sl@0
  1211
			
sl@0
  1212
			if ($t eq "struct" or $t eq "class" or $t eq "NONSHARABLE_CLASS") {
sl@0
  1213
				next if ($state==0);
sl@0
  1214
				$state=0;
sl@0
  1215
				my %cl;
sl@0
  1216
				$cl{specifier}=$t;
sl@0
  1217
				$cl{scope}=$scope;
sl@0
  1218
				my @members;
sl@0
  1219
				my @typedefs;
sl@0
  1220
				$cl{members}=\@members;
sl@0
  1221
				$cl{typedefs}=\@typedefs;
sl@0
  1222
				$cl{FormatTables}=$scope->{FormatTables};
sl@0
  1223
				my $new_class = \%cl;
sl@0
  1224
				my $n;
sl@0
  1225
sl@0
  1226
				if ($t eq "NONSHARABLE_CLASS")
sl@0
  1227
					{
sl@0
  1228
					my $b = get_token($scope,$tokens,$line);
sl@0
  1229
					if ($b !~ /\(/) {die "Syntax error at line $$line\n";}
sl@0
  1230
					$n = get_token($scope,$tokens,$line);
sl@0
  1231
  				$b = get_token($scope,$tokens,$line);
sl@0
  1232
					if ($b !~ /\)/) {die "Syntax error at line $$line\n";}
sl@0
  1233
					}
sl@0
  1234
				else					
sl@0
  1235
					{
sl@0
  1236
					$n = get_token($scope,$tokens,$line);
sl@0
  1237
					}
sl@0
  1238
								
sl@0
  1239
				
sl@0
  1240
				if ($n !~ /\w+/) {
sl@0
  1241
					warn "Unnamed $t not supported at line $$line\n";
sl@0
  1242
					return;
sl@0
  1243
				}
sl@0
  1244
				$new_class->{name}=$n;
sl@0
  1245
				my @class_match = grep {$_->{name} eq $n} @classes;
sl@0
  1246
				my $exists = scalar(@class_match);
sl@0
  1247
				my $b = get_token($scope,$tokens,$line);
sl@0
  1248
				#skip inheritance etc until we get to a '{' or \ ';'
sl@0
  1249
				while ($b ne '{' && $b ne ';')
sl@0
  1250
					{
sl@0
  1251
			        $b = get_token($scope,$tokens,$line);
sl@0
  1252
			        die "Syntax error#2 at line $$line\n" if  (!defined $b);
sl@0
  1253
					}
sl@0
  1254
				if ($b eq ';') {
sl@0
  1255
					# forward declaration
sl@0
  1256
					push @classes, $new_class unless ($exists);
sl@0
  1257
					next;
sl@0
  1258
				} 
sl@0
  1259
				if ($exists) {
sl@0
  1260
					$new_class = $class_match[0];
sl@0
  1261
					if ($new_class->{complete}) {
sl@0
  1262
						warn "Duplicate definition of $cl{specifier} $n\n";
sl@0
  1263
					}
sl@0
  1264
				}
sl@0
  1265
				push @classes, $new_class unless ($exists);
sl@0
  1266
				parse_scope($new_class, $tokens, $line);
sl@0
  1267
				next;
sl@0
  1268
			} elsif ($t eq "enum") {
sl@0
  1269
				$state=0;
sl@0
  1270
				my $n = get_token($scope,$tokens,$line);
sl@0
  1271
				my $name="";
sl@0
  1272
				if ($n =~ /\w+/) {
sl@0
  1273
					$name = $n;
sl@0
  1274
					$n = get_token($scope,$tokens,$line);
sl@0
  1275
				}
sl@0
  1276
				push @enums, $name;
sl@0
  1277
				if ($n ne '{') {
sl@0
  1278
					die "Syntax error#4 at line $$line\n";
sl@0
  1279
				}
sl@0
  1280
				parse_enum($scope, $tokens, $line, $name);
sl@0
  1281
				next;
sl@0
  1282
			} elsif ($t eq '}') {
sl@0
  1283
				$state=0;
sl@0
  1284
				if ($scope->{scope}) {
sl@0
  1285
			        if ($scope->{specifier} eq "namespace")
sl@0
  1286
			        	{
sl@0
  1287
						$scope->{complete}=1;
sl@0
  1288
#						print "Scope completed\n";
sl@0
  1289
						last;
sl@0
  1290
						}
sl@0
  1291
					$t = get_token($scope,$tokens,$line);
sl@0
  1292
					# skip to next ';'
sl@0
  1293
					while (defined ($t) and $t ne ';')
sl@0
  1294
						{$t = get_token($scope,$tokens,$line);}
sl@0
  1295
					die "Syntax error#5 at line $$line\n" if ($t ne ';');
sl@0
  1296
					$scope->{complete}=1;
sl@0
  1297
#					print "Scope completed\n";
sl@0
  1298
					last;
sl@0
  1299
				}
sl@0
  1300
				warn "Syntax error#5 at line $$line\n";
sl@0
  1301
				return;
sl@0
  1302
			}
sl@0
  1303
			$state=0;
sl@0
  1304
			if ($scope->{scope}) {
sl@0
  1305
				if ($t eq "public" or $t eq "private" or $t eq "protected") {
sl@0
  1306
					if (shift (@$tokens) eq ':') {
sl@0
  1307
						next;	# ignore access specifiers
sl@0
  1308
					}
sl@0
  1309
				die "Syntax error#6 at line $$line\n";
sl@0
  1310
				}
sl@0
  1311
			}
sl@0
  1312
			unshift @$tokens, $t;
sl@0
  1313
			
sl@0
  1314
			my @currdecl = parse_decl_def($scope, $tokens, $line);
sl@0
  1315
#			print scalar (@currdecl), "\n";
sl@0
  1316
			if ($t eq 'static') {
sl@0
  1317
				next;	# skip static members
sl@0
  1318
			}
sl@0
  1319
			my $typedef;
sl@0
  1320
			if ($t eq 'typedef') {
sl@0
  1321
#			print "TYPEDEF\n";
sl@0
  1322
				$typedef = 1;
sl@0
  1323
				$t = shift @currdecl;
sl@0
  1324
				$t = $currdecl[0];
sl@0
  1325
			} else {
sl@0
  1326
#			print "NOT TYPEDEF\n";
sl@0
  1327
				$typedef = 0;
sl@0
  1328
			}
sl@0
  1329
#			print "$currdecl[0]\n";
sl@0
  1330
			next if (scalar(@currdecl)==0);
sl@0
  1331
			
sl@0
  1332
			if ($t eq "const") {
sl@0
  1333
				# check for constant declaration
sl@0
  1334
#				print "CONST $currdecl[1] $currdecl[2] $currdecl[3]\n";
sl@0
  1335
				my $ctype = lookup_type($scope, $currdecl[1]);
sl@0
  1336
#				print "$ctype->{basic}    $ctype->{size}\n";
sl@0
  1337
				if ($ctype->{basic} and $currdecl[2]=~/^\w+$/ and $currdecl[3] eq '=') {
sl@0
  1338
					if ($typedef!=0) {
sl@0
  1339
						die "Syntax error#7 at line $$line\n";
sl@0
  1340
					}
sl@0
  1341
					shift @currdecl;
sl@0
  1342
					shift @currdecl;
sl@0
  1343
					my $type = $ctype->{name};
sl@0
  1344
					my $name;		#### = shift @currdecl;
sl@0
  1345
sl@0
  1346
					if ($scope->{name})
sl@0
  1347
						{	
sl@0
  1348
						$name = $scope->{name} . "::" . shift @currdecl;
sl@0
  1349
						}
sl@0
  1350
					else
sl@0
  1351
						{
sl@0
  1352
						$name = shift @currdecl;
sl@0
  1353
						}
sl@0
  1354
#					printf "[$name,$scope->{name}]";
sl@0
  1355
					my $size = $ctype->{size};
sl@0
  1356
					shift @currdecl;
sl@0
  1357
					my $value = get_constant_expr($scope,\@currdecl,$line);
sl@0
  1358
					$values{$name} = {type=>$type, size=>$size, value=>$value};
sl@0
  1359
					next;
sl@0
  1360
				}
sl@0
  1361
			}
sl@0
  1362
			
sl@0
  1363
			
sl@0
  1364
			
sl@0
  1365
		}
sl@0
  1366
	}
sl@0
  1367
	
sl@0
  1368
	sub get_token($$$) {
sl@0
  1369
		my ($scope,$tokenlist,$line) = @_;
sl@0
  1370
		while (scalar(@$tokenlist)) {
sl@0
  1371
			my $t = shift @$tokenlist;
sl@0
  1372
			return $t if (!defined($t));
sl@0
  1373
			if (parse_doxygen($scope,$tokenlist, $line, $t) == 1)
sl@0
  1374
				{next;}
sl@0
  1375
			if ($t !~ /^[\s]*$/)
sl@0
  1376
				{
sl@0
  1377
				if ($$tokenlist[0] eq ":" and $$tokenlist[1] eq ":")
sl@0
  1378
					{
sl@0
  1379
					$t.= shift @$tokenlist;
sl@0
  1380
					$t.= shift @$tokenlist;
sl@0
  1381
					$t.= shift @$tokenlist;
sl@0
  1382
#					print "Colon-separated token";
sl@0
  1383
					}
sl@0
  1384
				return $t
sl@0
  1385
				}
sl@0
  1386
			++$$line;
sl@0
  1387
		}
sl@0
  1388
  		return undef;
sl@0
  1389
	}
sl@0
  1390
	
sl@0
  1391
	sub skip_qualifiers($) {
sl@0
  1392
		my ($tokens) = @_;
sl@0
  1393
		my $f=0;
sl@0
  1394
		my %quals = (
sl@0
  1395
			EXPORT_C => 1,
sl@0
  1396
			IMPORT_C => 1,
sl@0
  1397
			inline => 1,
sl@0
  1398
			virtual => 0,
sl@0
  1399
			const => 0,
sl@0
  1400
			volatile => 0,
sl@0
  1401
			static => 0,
sl@0
  1402
			extern => 0,
sl@0
  1403
			LOCAL_C => 0,
sl@0
  1404
			LOCAL_D => 0,
sl@0
  1405
			GLDEF_C => 0,
sl@0
  1406
			GLREF_C => 0,
sl@0
  1407
			GLDEF_D => 0,
sl@0
  1408
			GLREF_D => 0
sl@0
  1409
			);
sl@0
  1410
		for (;;) {
sl@0
  1411
			my $t = $$tokens[0];
sl@0
  1412
			my $q = $quals{$t};
sl@0
  1413
			last unless (defined ($q));
sl@0
  1414
			$f |= $q;
sl@0
  1415
			shift @$tokens;
sl@0
  1416
		}
sl@0
  1417
		return $f;
sl@0
  1418
	}
sl@0
  1419
	
sl@0
  1420
	sub parse_indirection($) {
sl@0
  1421
		my ($tokens) = @_;
sl@0
  1422
		my $level = 0;
sl@0
  1423
		for (;;) {
sl@0
  1424
			my $t = $$tokens[0];
sl@0
  1425
			if ($t eq '*') {
sl@0
  1426
				++$level;
sl@0
  1427
				shift @$tokens;
sl@0
  1428
				next;
sl@0
  1429
			}
sl@0
  1430
			last if ($t ne "const" and $t ne "volatile");
sl@0
  1431
			shift @$tokens;
sl@0
  1432
		}
sl@0
  1433
		return $level;
sl@0
  1434
	}
sl@0
  1435
	
sl@0
  1436
	sub get_operand($$$) {
sl@0
  1437
		my ($scope,$tokens,$line) = @_;
sl@0
  1438
		my $t = get_token($scope,$tokens,$line);
sl@0
  1439
		if ($t eq '-') {
sl@0
  1440
			my $x = get_operand($scope,$tokens,$line);
sl@0
  1441
			return -$x;
sl@0
  1442
		} elsif ($t eq '+') {
sl@0
  1443
			my $x = get_operand($scope,$tokens,$line);
sl@0
  1444
			return $x;
sl@0
  1445
		} elsif ($t eq '~') {
sl@0
  1446
			my $x = get_operand($scope,$tokens,$line);
sl@0
  1447
			return ~$x;
sl@0
  1448
		} elsif ($t eq '!') {
sl@0
  1449
			my $x = get_operand($scope,$tokens,$line);
sl@0
  1450
			return $x ? 0 : 1;
sl@0
  1451
		} elsif ($t eq '(') {
sl@0
  1452
			my $x = get_constant_expr($scope,$tokens,$line);
sl@0
  1453
			my $t = get_token($scope,$tokens,$line);
sl@0
  1454
			if ($t ne ')') {
sl@0
  1455
				warn "Missing ) at line $$line\n";
sl@0
  1456
				return undefined;
sl@0
  1457
			}
sl@0
  1458
			return $x;
sl@0
  1459
		} elsif ($t eq "sizeof") {
sl@0
  1460
			my $ident = get_token($scope,$tokens,$line);
sl@0
  1461
			if ($ident eq '(') {
sl@0
  1462
				$ident = get_token($scope,$tokens,$line);
sl@0
  1463
				my $cb = get_token($scope,$tokens,$line);
sl@0
  1464
				if ($cb ne ')') {
sl@0
  1465
					warn "Bad sizeof() syntax at line $$line\n";
sl@0
  1466
					return undefined;
sl@0
  1467
				}
sl@0
  1468
			}
sl@0
  1469
			$ident = look_through_macros($ident);
sl@0
  1470
			if ($ident !~ /^\w+$/) {
sl@0
  1471
				warn "Bad sizeof() syntax at line $$line\n";
sl@0
  1472
				return undefined;
sl@0
  1473
			}
sl@0
  1474
			my $type = lookup_type($scope, $ident);
sl@0
  1475
			if (!defined $type) {
sl@0
  1476
				warn "Unrecognised type $ident at line $$line\n";
sl@0
  1477
				return undefined;
sl@0
  1478
			}
sl@0
  1479
			if ($type->{basic}) {
sl@0
  1480
				return $type->{size};
sl@0
  1481
			} elsif ($type->{enum}) {
sl@0
  1482
				return 4;
sl@0
  1483
			} elsif ($type->{ptr}) {
sl@0
  1484
				return 4;
sl@0
  1485
			} elsif ($type->{fptr}) {
sl@0
  1486
				return 4;
sl@0
  1487
			}
sl@0
  1488
			my $al = $type->{class}->{align};
sl@0
  1489
			my $sz = $type->{class}->{size};
sl@0
  1490
			return ($sz+$al-1)&~($al-1);
sl@0
  1491
		}
sl@0
  1492
		$t = look_through_macros($t);
sl@0
  1493
		if ($t =~ /^0x/i) {
sl@0
  1494
			return oct($t);
sl@0
  1495
		} elsif ($t =~ /^\d/) {
sl@0
  1496
			return $t;
sl@0
  1497
		} elsif ($t =~ /^\w+$/) {
sl@0
  1498
			my $x = lookup_value($scope,$t);
sl@0
  1499
#			die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
sl@0
  1500
			if (!defined($x)) {
sl@0
  1501
				print "Unrecognised identifier '$t' at line $$line\n" ;
sl@0
  1502
			}
sl@0
  1503
			return $x;
sl@0
  1504
		} elsif ($t =~ /^\w+::\w+$/) {
sl@0
  1505
			my $x = lookup_value($scope,$t);
sl@0
  1506
#			die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
sl@0
  1507
			if (!defined($x)) {
sl@0
  1508
				print "Unrecognised identifier '$t' at line $$line\n" ;
sl@0
  1509
			}
sl@0
  1510
			return $x;
sl@0
  1511
		} else {
sl@0
  1512
			warn "Syntax error#10 at line $$line\n";
sl@0
  1513
			return undefined;
sl@0
  1514
		}
sl@0
  1515
	}
sl@0
  1516
	
sl@0
  1517
	sub look_through_macros($) {
sl@0
  1518
		my ($ident) = @_;
sl@0
  1519
		while ($ident and $macros{$ident}) {
sl@0
  1520
			$ident = $macros{$ident};
sl@0
  1521
		}
sl@0
  1522
		return $ident;
sl@0
  1523
	}
sl@0
  1524
	
sl@0
  1525
	sub lookup_value($$) {
sl@0
  1526
		my ($scope,$ident) = @_;
sl@0
  1527
		while ($scope) {
sl@0
  1528
			my $vl = $scope->{values};
sl@0
  1529
			if (defined($vl->{$ident})) {
sl@0
  1530
				return $vl->{$ident}->{value};
sl@0
  1531
			}
sl@0
  1532
			$scope = $scope->{scope};
sl@0
  1533
		}
sl@0
  1534
		return undef();
sl@0
  1535
	}
sl@0
  1536
	
sl@0
  1537
	sub lookup_type($$) {
sl@0
  1538
		my ($scope,$ident) = @_;
sl@0
  1539
		if ($basictypes{$ident}) {
sl@0
  1540
			return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
sl@0
  1541
		}
sl@0
  1542
		while ($scope) {
sl@0
  1543
			if ($basictypes{$ident}) {
sl@0
  1544
				return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
sl@0
  1545
			}
sl@0
  1546
			my $el = $scope->{enums};
sl@0
  1547
			my $cl = $scope->{classes};
sl@0
  1548
			my $td = $scope->{typedefs};
sl@0
  1549
			if (grep {$_ eq $ident} @$el) {
sl@0
  1550
				return {scope=>$scope, enum=>1, name=>$ident, size=>4 };
sl@0
  1551
			}
sl@0
  1552
			my @match_class = (grep {$_->{name} eq $ident} @$cl);
sl@0
  1553
			if (scalar(@match_class)) {
sl@0
  1554
				return {scope=>$scope, class=>$match_class[0]};
sl@0
  1555
			}
sl@0
  1556
			my @match_td = (grep {$_->{name} eq $ident} @$td);
sl@0
  1557
			if (scalar(@match_td)) {
sl@0
  1558
				my $tdr = $match_td[0];
sl@0
  1559
				my $cat = $tdr->{category};
sl@0
  1560
				if ($cat eq 'basic' or $cat eq 'enum' or $cat eq 'class') {
sl@0
  1561
					$ident = $tdr->{alias};
sl@0
  1562
					next;
sl@0
  1563
				} else {
sl@0
  1564
					return { scope=>$scope, $cat=>1, $size=>$tdr->{size} };
sl@0
  1565
				}
sl@0
  1566
			}
sl@0
  1567
			$scope = $scope->{scope};
sl@0
  1568
		}
sl@0
  1569
		return undef();
sl@0
  1570
	}
sl@0
  1571
	
sl@0
  1572
	sub get_mult_expr($$$) {
sl@0
  1573
		my ($scope,$tokens,$line) = @_;
sl@0
  1574
		my $x = get_operand($scope,$tokens,$line);
sl@0
  1575
		my $t;
sl@0
  1576
		for (;;) {
sl@0
  1577
			$t = get_token($scope,$tokens,$line);
sl@0
  1578
			if ($t eq '*') {
sl@0
  1579
				my $y = get_operand($scope,$tokens,$line);
sl@0
  1580
				$x = $x * $y;
sl@0
  1581
			} elsif ($t eq '/') {
sl@0
  1582
				my $y = get_operand($scope,$tokens,$line);
sl@0
  1583
				if ($y != 0)
sl@0
  1584
					{$x = int($x / $y);}
sl@0
  1585
			} elsif ($t eq '%') {
sl@0
  1586
				my $y = get_operand($scope,$tokens,$line);
sl@0
  1587
				if ($y != 0)
sl@0
  1588
					{$x = int($x % $y);}
sl@0
  1589
			} else {
sl@0
  1590
				last;
sl@0
  1591
			}
sl@0
  1592
		}
sl@0
  1593
		unshift @$tokens, $t;
sl@0
  1594
		return $x;
sl@0
  1595
	}
sl@0
  1596
	
sl@0
  1597
	sub get_add_expr($$$) {
sl@0
  1598
		my ($scope,$tokens,$line) = @_;
sl@0
  1599
		my $x = get_mult_expr($scope,$tokens,$line);
sl@0
  1600
		my $t;
sl@0
  1601
		for (;;) {
sl@0
  1602
			$t = get_token($scope,$tokens,$line);
sl@0
  1603
			if ($t eq '+') {
sl@0
  1604
				my $y = get_mult_expr($scope,$tokens,$line);
sl@0
  1605
				$x = $x + $y;
sl@0
  1606
			} elsif ($t eq '-') {
sl@0
  1607
				my $y = get_mult_expr($scope,$tokens,$line);
sl@0
  1608
				$x = $x - $y;
sl@0
  1609
			} else {
sl@0
  1610
				last;
sl@0
  1611
			}
sl@0
  1612
		}
sl@0
  1613
		unshift @$tokens, $t;
sl@0
  1614
		return $x;
sl@0
  1615
	}
sl@0
  1616
	
sl@0
  1617
	sub get_shift_expr($$$) {
sl@0
  1618
		my ($scope,$tokens,$line) = @_;
sl@0
  1619
		my $x = get_add_expr($scope,$tokens,$line);
sl@0
  1620
		my $t, $t2;
sl@0
  1621
		for (;;) {
sl@0
  1622
			$t = get_token($scope,$tokens,$line);
sl@0
  1623
			if ($t eq '<' or $t eq '>') {
sl@0
  1624
				$t2 = get_token($scope,$tokens,$line);
sl@0
  1625
				if ($t2 ne $t) {
sl@0
  1626
					unshift @$tokens, $t2;
sl@0
  1627
					last;
sl@0
  1628
				}
sl@0
  1629
			}
sl@0
  1630
			if ($t eq '<') {
sl@0
  1631
				my $y = get_add_expr($scope,$tokens,$line);
sl@0
  1632
				$x = $x << $y;
sl@0
  1633
			} elsif ($t eq '>') {
sl@0
  1634
				my $y = get_add_expr($scope,$tokens,$line);
sl@0
  1635
				$x = $x >> $y;
sl@0
  1636
			} else {
sl@0
  1637
				last;
sl@0
  1638
			}
sl@0
  1639
		}
sl@0
  1640
		unshift @$tokens, $t;
sl@0
  1641
		return $x;
sl@0
  1642
	}
sl@0
  1643
	
sl@0
  1644
	sub get_and_expr($$$) {
sl@0
  1645
		my ($scope,$tokens,$line) = @_;
sl@0
  1646
		my $x = get_shift_expr($scope,$tokens,$line);
sl@0
  1647
		my $t;
sl@0
  1648
		for (;;) {
sl@0
  1649
			$t = get_token($scope,$tokens,$line);
sl@0
  1650
			if ($t eq '&') {
sl@0
  1651
				my $y = get_shift_expr($scope,$tokens,$line);
sl@0
  1652
				$x = $x & $y;
sl@0
  1653
			} else {
sl@0
  1654
				last;
sl@0
  1655
			}
sl@0
  1656
		}
sl@0
  1657
		unshift @$tokens, $t;
sl@0
  1658
		return $x;
sl@0
  1659
	}
sl@0
  1660
	
sl@0
  1661
	sub get_xor_expr($$$) {
sl@0
  1662
		my ($scope,$tokens,$line) = @_;
sl@0
  1663
		my $x = get_and_expr($scope,$tokens,$line);
sl@0
  1664
		my $t;
sl@0
  1665
		for (;;) {
sl@0
  1666
			$t = get_token($scope,$tokens,$line);
sl@0
  1667
			if ($t eq '^') {
sl@0
  1668
				my $y = get_and_expr($scope,$tokens,$line);
sl@0
  1669
				$x = $x ^ $y;
sl@0
  1670
			} else {
sl@0
  1671
				last;
sl@0
  1672
			}
sl@0
  1673
		}
sl@0
  1674
		unshift @$tokens, $t;
sl@0
  1675
		return $x;
sl@0
  1676
	}
sl@0
  1677
	
sl@0
  1678
	sub get_ior_expr($$$) {
sl@0
  1679
		my ($scope,$tokens,$line) = @_;
sl@0
  1680
		my $x = get_xor_expr($scope,$tokens,$line);
sl@0
  1681
		my $t;
sl@0
  1682
		for (;;) {
sl@0
  1683
			$t = get_token($scope,$tokens,$line);
sl@0
  1684
			if ($t eq '|') {
sl@0
  1685
				my $y = get_xor_expr($scope,$tokens,$line);
sl@0
  1686
				$x = $x | $y;
sl@0
  1687
			} else {
sl@0
  1688
				last;
sl@0
  1689
			}
sl@0
  1690
		}
sl@0
  1691
		unshift @$tokens, $t;
sl@0
  1692
		return $x;
sl@0
  1693
	}
sl@0
  1694
	
sl@0
  1695
	sub get_constant_expr($$$) {
sl@0
  1696
		my ($scope,$tokens,$line) = @_;
sl@0
  1697
		my $x = get_ior_expr($scope,$tokens,$line);
sl@0
  1698
		return $x;
sl@0
  1699
	}
sl@0
  1700
	
sl@0
  1701
	sub parse_enum($$$$) {
sl@0
  1702
		my ($scope,$tokens,$line,$enum_name) = @_;
sl@0
  1703
		my $vl = $scope->{values};
sl@0
  1704
		my $fstr = $scope->{formatStrings};
sl@0
  1705
		my $fcat = $scope->{formatCategories};
sl@0
  1706
		my $fmtTable = $scope->{FormatTables};
sl@0
  1707
		
sl@0
  1708
		my $x = 0;
sl@0
  1709
		for (;;) {
sl@0
  1710
			my $t = get_token($scope,$tokens,$line);
sl@0
  1711
			last if ($t eq '}');
sl@0
  1712
			if (!defined($t)) {
sl@0
  1713
				die "Unexpected end of file #2 at line $$line\n";
sl@0
  1714
			}
sl@0
  1715
			
sl@0
  1716
			if ($t eq '#') {
sl@0
  1717
				next;
sl@0
  1718
				}
sl@0
  1719
			
sl@0
  1720
			if ($t !~ /^\w+$/) {
sl@0
  1721
				warn "Syntax error#11 at line $$line\n";
sl@0
  1722
				next;
sl@0
  1723
			}
sl@0
  1724
sl@0
  1725
			if ($scope->{name})
sl@0
  1726
				{	
sl@0
  1727
				$t = $scope->{name} . "::" . $t;
sl@0
  1728
				}
sl@0
  1729
sl@0
  1730
			if (defined($vl->{$t})) {
sl@0
  1731
				warn "Duplicate identifier [$t] at line $$line\n";
sl@0
  1732
			}
sl@0
  1733
			my $t2 = get_token($scope,$tokens,$line);
sl@0
  1734
			if ($t2 eq ',') {
sl@0
  1735
				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
sl@0
  1736
				$fstr->{$t} = $CurrentTraceFormatString; 
sl@0
  1737
				$fcat->{$t} = $CurrentTraceFormatCategory; 
sl@0
  1738
				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
sl@0
  1739
					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
sl@0
  1740
				undef $CurrentTraceFormatString;
sl@0
  1741
				++$x;
sl@0
  1742
			} elsif ($t2 eq '}') {
sl@0
  1743
				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
sl@0
  1744
				$fstr->{$t} = $CurrentTraceFormatString; 
sl@0
  1745
				$fcat->{$t} = $CurrentTraceFormatCategory; 
sl@0
  1746
				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
sl@0
  1747
					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
sl@0
  1748
				undef $CurrentTraceFormatString;
sl@0
  1749
				++$x;
sl@0
  1750
				last;
sl@0
  1751
			} elsif ($t2 eq '=') {
sl@0
  1752
				$x = get_constant_expr($scope, $tokens, $line);
sl@0
  1753
				$vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
sl@0
  1754
				$fstr->{$t} = $CurrentTraceFormatString; 
sl@0
  1755
				$fcat->{$t} = $CurrentTraceFormatCategory;
sl@0
  1756
				if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
sl@0
  1757
					{ $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
sl@0
  1758
				undef $CurrentTraceFormatString; 
sl@0
  1759
				++$x;
sl@0
  1760
				$t2 = get_token($scope,$tokens,$line);
sl@0
  1761
				last if ($t2 eq '}');
sl@0
  1762
				next if ($t2 eq ',');
sl@0
  1763
				warn "Syntax error#12 at line $$line\n";
sl@0
  1764
			} else {
sl@0
  1765
				unshift @$tokens, $t2;
sl@0
  1766
			}
sl@0
  1767
		}
sl@0
  1768
		my $t = get_token($scope,$tokens,$line);
sl@0
  1769
		if ($t ne ';') {
sl@0
  1770
			warn "Missing ; at line $$line\n";
sl@0
  1771
		}
sl@0
  1772
	}
sl@0
  1773
	
sl@0
  1774
	
sl@0
  1775
	sub  parse_decl_def($$$) {
sl@0
  1776
		my ($scope,$tokens,$line) = @_;
sl@0
  1777
		my $level=0;
sl@0
  1778
		my @decl;
sl@0
  1779
		while ( scalar(@$tokens) ) {
sl@0
  1780
			my $t = get_token($scope,$tokens, $line);
sl@0
  1781
			if ( (!defined ($t) || $t eq ';') and ($level==0)) {
sl@0
  1782
				return @decl;
sl@0
  1783
			}
sl@0
  1784
	
sl@0
  1785
			if ($t eq "static")
sl@0
  1786
				{
sl@0
  1787
				next;
sl@0
  1788
				}
sl@0
  1789
	
sl@0
  1790
			push @decl, $t;
sl@0
  1791
			if ($t eq '{') {
sl@0
  1792
				++$level;
sl@0
  1793
			}
sl@0
  1794
			if ($t eq '}') {
sl@0
  1795
				if ($level==0) {
sl@0
  1796
					warn "Syntax error#13 at line $$line\n";
sl@0
  1797
					unshift @$tokens, $t;
sl@0
  1798
					return @decl;
sl@0
  1799
					
sl@0
  1800
				}
sl@0
  1801
				if (--$level==0) {
sl@0
  1802
					return ();	# end of function definition reached
sl@0
  1803
				}
sl@0
  1804
			}
sl@0
  1805
		}
sl@0
  1806
		die "Unexpected end of file #3 at line $$line\n";
sl@0
  1807
	}
sl@0
  1808
	
sl@0
  1809
	sub dump_scope($) {
sl@0
  1810
		my ($scope) = @_;
sl@0
  1811
		my $el = $scope->{enums};
sl@0
  1812
		my $cl = $scope->{classes};
sl@0
  1813
		my $vl = $scope->{values};
sl@0
  1814
		my $fstr = $scope->{formatStrings};
sl@0
  1815
		my $fcat = $scope->{formatCategories};
sl@0
  1816
		print "SCOPE: $scope->{name}\n";
sl@0
  1817
		if (scalar(@$el)) {
sl@0
  1818
			print "\tenums:\n";
sl@0
  1819
			foreach (@$el) {
sl@0
  1820
				print "\t\t$_\n";
sl@0
  1821
			}
sl@0
  1822
		}
sl@0
  1823
		if (scalar(keys(%$vl))) {
sl@0
  1824
			print "\tvalues:\n";
sl@0
  1825
			foreach $vname (keys(%$vl)) {
sl@0
  1826
				my $v = $vl->{$vname};
sl@0
  1827
				my $x = $v->{value};
sl@0
  1828
				my $t = $v->{type};
sl@0
  1829
				my $sz = $v->{size};
sl@0
  1830
				my $fstring = $fstr->{$vname};
sl@0
  1831
				my $fcategory = $fcat->{$vname};
sl@0
  1832
				if ($v->{enum}) {
sl@0
  1833
					printf ("\t\t$vname\=$x (enum $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory,$fstring);
sl@0
  1834
				} else {
sl@0
  1835
					printf ("\t\t$vname\=$x (type $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory, $fstring);
sl@0
  1836
				}
sl@0
  1837
			}
sl@0
  1838
		}
sl@0
  1839
		if ($scope->{scope}) {
sl@0
  1840
			my $members = $scope->{members};
sl@0
  1841
			foreach (@$members) {
sl@0
  1842
				my $n = $_->{name};
sl@0
  1843
				my $sz = $_->{size};
sl@0
  1844
				my $off = $_->{offset};
sl@0
  1845
				my $spc = $_->{spacing};
sl@0
  1846
				if (defined $spc) {
sl@0
  1847
					print "\t$n\[\]\: spacing $spc size $sz offset $off\n";
sl@0
  1848
				} else {
sl@0
  1849
					print "\t$n\: size $sz offset $off\n";
sl@0
  1850
				}
sl@0
  1851
			}
sl@0
  1852
			print "\tOverall size : $scope->{size}\n";
sl@0
  1853
			print "\tOverall align: $scope->{align}\n";
sl@0
  1854
		}
sl@0
  1855
		foreach $s (@$cl) {
sl@0
  1856
			dump_scope($s);
sl@0
  1857
		}
sl@0
  1858
	}
sl@0
  1859
	
sl@0
  1860
	
sl@0
  1861
	
sl@0
  1862
		
sl@0
  1863
	sub parse_doxygen($$$$) {
sl@0
  1864
		my ($scope,$tokens,$line,$t) = @_;
sl@0
  1865
	
sl@0
  1866
		if ($t ne "/")
sl@0
  1867
			{
sl@0
  1868
			return 0;	# not a doxygen comment
sl@0
  1869
			}
sl@0
  1870
		if ($t eq "/") {
sl@0
  1871
			$state=0;
sl@0
  1872
			my $t2 = shift @$tokens;
sl@0
  1873
			my $t3 = shift @$tokens;
sl@0
  1874
	
sl@0
  1875
			if ($t2 ne "*" || $t3 ne "*")
sl@0
  1876
				{
sl@0
  1877
				unshift @$tokens, $t3;
sl@0
  1878
				unshift @$tokens, $t2;
sl@0
  1879
				return 0;	# not a doxygen comment
sl@0
  1880
				}
sl@0
  1881
		}
sl@0
  1882
#		printf "doxygen start on line %d\n", $$line;
sl@0
  1883
		for (;;) {
sl@0
  1884
			my $t = shift @$tokens;
sl@0
  1885
			if (!defined($t)) 
sl@0
  1886
					{
sl@0
  1887
					warn "Unexpected end of file #4 at line $$line\n";	
sl@0
  1888
					return
sl@0
  1889
					}
sl@0
  1890
			
sl@0
  1891
			if ($t eq "\n"){++$$line };
sl@0
  1892
			
sl@0
  1893
			if ($t eq '*')
sl@0
  1894
				{
sl@0
  1895
				my $t2 = shift @$tokens;
sl@0
  1896
				last if ($t2 eq '/');
sl@0
  1897
				unshift @$tokens, $t2;
sl@0
  1898
				}
sl@0
  1899
			
sl@0
  1900
			if ($t eq '@')
sl@0
  1901
				{
sl@0
  1902
				my $t2 = shift @$tokens;
sl@0
  1903
				if ($t2 eq 'SYMTraceFormatString')
sl@0
  1904
					{
sl@0
  1905
					my $t3 = shift @$tokens;
sl@0
  1906
#					if ($VerboseMode){print "SYMTraceFormatString = [$t3]\n";}
sl@0
  1907
					$CurrentTraceFormatString = $t3;
sl@0
  1908
					}
sl@0
  1909
				if ($t2 eq 'SYMTraceFormatCategory')
sl@0
  1910
					{
sl@0
  1911
					$CurrentTraceFormatCategory = get_operand($scope,$tokens,$line);
sl@0
  1912
#					if ($VerboseMode){printf ("SYMTraceFormatCategory = 0x%x\n", $CurrentTraceFormatCategory);}
sl@0
  1913
					}
sl@0
  1914
				else
sl@0
  1915
					{
sl@0
  1916
					unshift @$tokens, $t2;
sl@0
  1917
					}
sl@0
  1918
				}
sl@0
  1919
	
sl@0
  1920
		}
sl@0
  1921
#		printf ("doxygen end  on line %d\n", $$line);
sl@0
  1922
		return 1;	# is a doxygen comment
sl@0
  1923
	}
sl@0
  1924
	
sl@0
  1925
sl@0
  1926
        
sl@0
  1927
        
sl@0
  1928
        
sl@0
  1929
        
sl@0
  1930
        
sl@0
  1931
        
sl@0
  1932
        
sl@0
  1933
        
sl@0
  1934
        
sl@0
  1935
        
sl@0
  1936
        
sl@0
  1937
        
sl@0
  1938
        
sl@0
  1939
        
sl@0
  1940
        
sl@0
  1941
        
sl@0
  1942
        
sl@0
  1943
        
sl@0
  1944
        
sl@0
  1945
        
sl@0
  1946
        
sl@0
  1947
        
sl@0
  1948
        
sl@0
  1949
        
sl@0
  1950
        
sl@0
  1951
        
sl@0
  1952