--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32utils/trace/btracevw.pl Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1952 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+
+#!/usr/bin/perl
+
+use File::Find;
+use File::Spec::Functions;
+
+
+ my $TraceFileName;
+
+ my $PrintFlagFilePos = 0;
+ my $PrintFlagHdrLen = 0;
+ my $PrintFlagHdrFlags = 0;
+ my $PrintFlagFormatString = 0;
+ my $VerboseMode = 0;
+ my $RawMode = 0;
+ my $FormatIdIsSubCategory = 0;
+ my $OutputSawDictionaryMode = 0;
+
+ # for the category range 0-191, the format string is indexed by the category & subcategory
+ %FormatTables =
+ (
+ 0 => # ERDebugPrintf
+ {
+ 0 => "ThreadId %h, %s",
+ },
+
+ 1 => # ERKernPrintf
+ {
+ 0 => "ThreadId %h, %s",
+ },
+
+ 3 => # EThreadIdentification
+ {
+ 0 => "ENanoThreadCreate, NThread %x",
+ 1 => "ENanoThreadDestroy, NThread %x",
+ 2 => "EThreadCreate, NThread %x, DProcess %x, name %s",
+ 3 => "EThreadDestroy, NThread %x, DProcess %x, Id %x",
+ 4 => "EThreadName, NThread %x, DProcess %x, name %s",
+ 5 => "EProcessName, NThread %x, DProcess %x, name %s",
+ 6 => "EThreadId, NThread %x, DProcess %x, Id %x",
+ 7 => "EProcessCreate, DProcess %x",
+ 8 => "EProcessDestroy, DProcess %x",
+ },
+ );
+
+ my @typedefs;
+ my @members;
+ my %values = (
+# UTF::KInitialClientFormat => {type=>"TFormatId", size=>2, value=>512}
+ KMaxTUint8 => {type=>"TUint8", size=>1, value=>255},
+ KMaxTUint16 => {type=>"TUint16", size=>2, value=>65535}
+ );
+ my %macros;
+ my @classes;
+ my @enums;
+ my %formatStrings; # each enum may have it's own format string
+ my %formatCategories; # each enum may have it's own format category
+
+ my %filescope;
+ $filescope{file}=1;
+ undef $filescope{name};
+
+ $filescope{typedefs}=\@typedefs;
+ $filescope{members}=\@members;
+ $filescope{values}=\%values;
+ $filescope{macros} = \%macros;
+ $filescope{FormatTables} = \%FormatTables;
+
+ $filescope{classes} = \@classes;
+ $filescope{enums} = \@enums;
+
+ $filescope{formatStrings} =\%formatStrings;
+ $filescope{formatCategories} = \%formatCategories;
+
+
+
+ if (@ARGV == 0)
+ {
+ print "BTraceVw.pl \n";
+ print "An unsupported utility which extracts UTrace-style format-strings\n";
+ print "from header files & uses these to decode a BTrace output file\n";
+ print "Syntax : BTraceVw.pl [-v] [-r] [-sd] [-i <IncFilePath>] [<BTrace file>]\n";
+ print "where : -v = verbose mode\n";
+ print " : -r = raw output mode\n";
+ print " : -sd = produce SAW trace viewer dictionary file\n";
+ print " : this file then needs to be merged into the 'com.symbian.analysis.trace.ui.prefs' file\n";
+ print " : located under the carbide workspace directory\n";
+ print "\n";
+
+ print "e.g. (this decodes a trace file & produces a comma-separated output file) : \n";
+ 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";
+ print "\n";
+ print "e.g. (this overwrites the SAW dictioany file) : \n";
+ 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";
+
+ exit;
+ }
+
+ while (@ARGV > 0)
+ {
+
+ if ($ARGV[0] eq "-i")
+ {
+ shift @ARGV;
+ ($FilePath) = @ARGV;
+ shift @ARGV;
+
+ undef @incFiles;
+ @incFiles;
+
+ find sub { push @incFiles, $File::Find::name if m/\.h$/i;}, $FilePath ;
+ foreach $incFile (@incFiles)
+ {
+ H2Trace($incFile, \%filescope);
+ }
+ }
+ elsif ($ARGV[0] eq "-r")
+ {
+ $RawMode = 1;
+ shift @ARGV;
+ }
+ elsif ($ARGV[0] eq "-sd")
+ {
+ $OutputSawDictionaryMode = 1;
+ shift @ARGV;
+ }
+ elsif ($ARGV[0] eq "-v")
+ {
+ $VerboseMode = 1;
+ shift @ARGV;
+ }
+ else
+ {
+ $TraceFileName = "$ARGV[0]";
+ shift @ARGV;
+ }
+ }
+
+ if ($VerboseMode)
+ {
+ dump_scope(\%filescope);
+ PrintFormatTables(\%FormatTables);
+ }
+ if ($OutputSawDictionaryMode)
+ {
+ OutputSawDictionary(\%FormatTables);
+ }
+
+ if (defined ($TraceFileName))
+ {
+ ReadTraceFile($RawMode);
+ }
+
+
+
+
+sub ReadTraceFile($)
+ {
+ (my $RawMode) = @_;
+# print "Trace file is $TraceFileName, RawMode $RawMode, VerboseMode $VerboseMode\n\n";
+
+ open (LOGFILE, "<$TraceFileName") or die "Can't open $TraceFileName: $!\n";
+ binmode (LOGFILE);
+
+ my $val = 0;
+
+
+ # enum TFlags from e32btrace.h
+ $EHeader2Present = 1<<0;
+ $ETimestampPresent = 1<<1;
+ $ETimestamp2Present = 1<<2;
+ $EContextIdPresent = 1<<3;
+ $EPcPresent = 1<<4;
+ $EExtraPresent = 1<<5;
+ $ERecordTruncated = 1<<6;
+ $EMissingRecord = 1<<7;
+
+ # enum TFlags2 from e32btrace.h
+ $EMultipartFlagMask = 3<<0;
+ $ECpuIdMask = 0xfff<<20;
+
+ # enum TMultiPart from e32btrace.h
+ $EMultipartFirst = 1;
+ $EMultipartMiddle = 2;
+ $EMultipartLast = 3;
+
+ $EMaxBTraceDataArray = 80;
+
+ # enum TCategory from e32btrace.h
+ $EThreadIdentification = 3;
+
+ # enum TThreadIdentification from e32btrace.h
+ $EThreadCreate = 2;
+ $EThreadName = 4;
+ $EProcessName = 5;
+ $EThreadId = 6;
+
+ # Context Id bits from e32btrace.h
+ $EContextIdMask = 0x00000003;
+ $EContextIdThread = 0;
+ $EContextIdFIQ = 0x1;
+ $EContextIdIRQ = 0x2;
+ $EContextIdIDFC = 0x3;
+
+ # enum TClassificationRange from e32btraceu.h
+ $EAllRangeFirst = 192;
+ $EAllRangeLast = 222;
+
+ %TCategoryIdToString =
+ (
+ 0 => "ERDebugPrintf",
+ 1 => "EKernPrintf",
+ 2 => "EPlatsecPrintf",
+ 3 => "EThreadIdentification",
+ 4 => "ECpuUsage",
+ 5 => "EKernPerfLog",
+ 6 => "EClientServer",
+ 7 => "ERequests",
+ 8 => "EChunks",
+ 9 => "ECodeSegs",
+ 10 => "EPaging",
+ 11 => "EThreadPriority",
+ 12 => "EPagingMedia",
+ 13 => "EKernelMemory",
+ 14 => "EHeap",
+ 15 => "EMetaTrace",
+ 16 => "ERamAllocator",
+ 17 => "EFastMutex",
+ 18 => "EProfiling",
+ 19 => "EResourceManager",
+ 20 => "EResourceManagerUs",
+ 21 => "ERawEvent ",
+ 128 => "EPlatformSpecificFirst",
+ 191 => "EPlatformSpecificLast",
+ 192 => "ESymbianExtentionsFirst",
+
+ # UTrace "ALL" range
+ 192 => "EPanic",
+ 193 => "EError",
+ 194 => "EWarning",
+ 195 => "EBorder",
+ 196 => "EState",
+ 197 => "EInternals",
+ 198 => "EDump",
+ 199 => "EFlow",
+ 200 => "ESystemCharacteristicMetrics",
+ 201 => "EAdhoc",
+
+ 253 => "ESymbianExtentionsLast",
+ 254 => "ETest1",
+ 255 => "ETest2",
+ );
+
+
+ %ProcessNames;
+ %ThreadNames;
+ %ThreadIds;
+
+
+ # print column titles
+ if ($PrintFlagFilePos) {printf "FilePos, ";} # col #0
+ if ($PrintFlagHdrLen) { printf "Len, ";} # col #1
+ if ($PrintFlagHdrFlags) {printf "Flags, "; } # col #2
+ printf "Category, "; # col #3
+ printf "TimeStamp, "; # col #4
+ printf "Delta, "; # col #5
+ printf "context Id, "; # col #6
+ printf "PC, "; # col #7
+ printf "UID, "; # col #8
+ if ($PrintFlagFormatString){printf "Format string, ";} # col #9
+ printf "Formatted text, "; # col #10
+ print "\n\n";
+
+
+ while (1)
+ {
+ my $pos = tell (LOGFILE);
+
+ # print file pos (col #0)
+ if ($PrintFlagFilePos){ printf ("0x%08X, ", $pos);}
+
+ my $category;
+ my $subCategory;
+ my $multipartFlags = 0;
+ my $recordData = "";
+ my $recordLen;
+ my $recordPos = 0;
+
+ $recordLen = ReadRecord(LOGFILE, \$pos, \$recordData, \$category, \$subCategory, \$multipartFlags, $RawMode);
+ if ($recordLen == -1)
+ {last;}
+
+
+ if (!$RawMode && ($multipartFlags == $EMultipartMiddle || $multipartFlags == $EMultipartLast))
+ {next;}
+
+# print record contents
+# my $buf;
+# for (my $i=0; $i < $recordLen; $i+=4)
+# {
+# $buf.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos+$i, 4)));
+# }
+# printf "\n[$buf\n]";
+
+
+ # for UTrace "ALL" range, read UID
+ if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast &&
+ (!$RawMode) && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
+ {
+ $uid = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+
+ # then read formatID
+ $FormatIdIsSubCategory = ($subCategory != 0) ? 1 : 0;
+ if ($FormatIdIsSubCategory)
+ {
+ $formatId = $subCategory
+ }
+ else
+ {
+ $formatId = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+ }
+ }
+
+
+ # print UID (col #8)
+ printf "0x%08X, ", $uid;
+
+
+ my $formatTable;
+ my $formatString;
+ if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast)
+ {
+ $formatString = $FormatTables{$uid}{$formatId};
+ }
+ else
+ {
+ $formatString = $FormatTables{$category}{$subCategory};
+ }
+
+
+ # Get thread names
+ if ($category == $EThreadIdentification)
+ {
+ if ($subCategory == $EProcessName)
+ {
+ my $process = unpack("V", substr($recordData, 4, 4));
+ my $processName = substr($recordData, 8, $recordLen - 8);
+# printf ("\nprocess [%08X] processName [$processName]\n", $process);
+ $ProcessNames{$process} = $processName;
+ }
+ elsif ($subCategory == $EThreadCreate || $subCategory == $EThreadName)
+ {
+ my $thread = unpack("V", substr($recordData, 0, 4));
+ my $process = unpack("V", substr($recordData, 4, 4));
+ my $threadName = substr($recordData, 8, $recordLen - 8);
+# printf ("\nprocess [%08X] thread [%08X] threadName [$threadName]\n", $process, $thread, $threadName);
+ $ThreadNames{$thread} = $ProcessNames{$process} . "::" . $threadName;
+ }
+ elsif ($subCategory == $EThreadId)
+ {
+ my $thread = unpack("V", substr($recordData, 0, 4));
+ my $process = unpack("V", substr($recordData, 4, 4));
+ my $threadId = unpack("V", substr($recordData, 8, 4));
+# printf ("\nprocess [%08X] thread [%08X] threadId [%08X]\n", $process, $thread, $threadId);
+ $ThreadIds{$thread} = $threadId;
+ }
+ }
+
+
+ # print Format string (col #9)
+ if ($PrintFlagFormatString)
+ {
+ my $formatStringWithoutCommas = $formatString;
+ $formatStringWithoutCommas=~ s/,/ /g;
+ printf "%s, ", $formatStringWithoutCommas;
+ }
+
+ my $formattedText;
+
+ my $lenFormatString = length($formatString);
+ if ($lenFormatString && !$RawMode && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
+ {
+ for (my $i=0; $i<$lenFormatString; $i++)
+ {
+ my $c = (substr ($formatString, $i, 1));
+# printf "$c\n";
+ if ($c eq "%")
+ {
+ undef my $fieldLen;
+ $i++;
+ $c = (substr ($formatString, $i, 1));
+ if ($c eq "%")
+ {
+ $formattedText.= substr ($formatString, $i, 1);
+ next;
+ }
+ if ($c eq "*") ## take length from buffer
+ {
+ $fieldLen = unpack("V", substr($recordData, $recordPos, 4));
+ if ($fieldLen > $recordLen-$recordPos)
+ {
+ $formattedText.= "*** Invalid field length ***";
+ last;
+ }
+ $recordPos+= 4;
+ $i++;
+ $c = (substr ($formatString, $i, 1));
+ }
+ if (lc $c eq "x" || $c eq "h")
+ {
+ if (defined $fieldLen)
+ {
+ if (($fieldLen & 3) == 0)
+ {
+ for (my $i=0; $i< $fieldLen; $i+= 4)
+ {
+ $formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos, 4)));
+ $recordPos+= 4;
+ }
+ }
+ else
+ {
+ for (my $i=0; $i< $fieldLen; $i++)
+ {
+ $formattedText.= sprintf ("%02X ", unpack("C", substr($recordData, $recordPos, 1)));
+ $recordPos++;
+ }
+ }
+ }
+ else
+ {
+ $formattedText.= sprintf ("0x%08X", unpack("V", substr($recordData, $recordPos, 4)));
+ $recordPos+= 4;
+ }
+ $recordPos = ($recordPos + 3) & ~3;
+ next;
+ }
+ # display "%ld" as hex for now as don't know how to get perl to use or display a 64 decimal value
+ elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "d")
+ {
+ $i++;
+ my $loWord = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+ my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+ $formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
+ }
+ elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "x")
+ {
+ $i++;
+ my $loWord = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+ my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
+ $recordPos+= 4;
+ $formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
+ }
+ elsif (lc $c eq "d")
+ {
+ $formattedText.= sprintf ("%d", unpack("V", substr($recordData, $recordPos, 4)));
+ $recordPos+= 4;
+ $recordPos = ($recordPos + 3) & ~3;
+ next;
+ }
+ elsif ($c eq "s")
+ {
+ if (!defined $fieldLen)
+ {$fieldLen = $recordLen - $recordPos;}
+ $formattedText.= substr($recordData, $recordPos, $fieldLen);
+ $recordPos+= $fieldLen;
+ $recordPos = ($recordPos + 3) & ~3;
+ next;
+ }
+ elsif ($c eq "S")
+ {
+ if (!defined $fieldLen)
+ {$fieldLen = $recordLen-$recordPos;}
+ for (my $j=0; $j < $fieldLen; $j+=2)
+ {
+ my $byte = unpack("c", substr ($recordData, $recordPos+$j, 1));
+ $formattedText.= sprintf ("%c", $byte);
+ }
+ $recordPos+= $fieldLen;
+ $recordPos = ($recordPos + 3) & ~3;
+ next;
+ }
+ elsif ($c eq "c")
+ {
+ my $byte = unpack("c", substr ($recordData, $recordPos, 1));
+ $formattedText.= sprintf ("%c", $byte);
+ }
+ }
+ else
+ {
+ $formattedText.= $c;
+ }
+ }
+ }
+ else # no format string : print as hex
+ {
+ for (my $i=0; $i < $recordLen; $i+=4)
+ {
+ $formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $i, 4)));
+ }
+ $recordPos+= $recordLen; $recordLen = 0;
+
+ }
+
+
+ # print Formatted text (col #10)
+ $formattedText=~ s/,/;/g;
+ $formattedText=~ s/\r//g;
+ $formattedText=~ s/\n/,/g;
+ printf "%s", $formattedText;
+
+ printf("\n");
+
+ if ($len < 0 || $recordLen < 0) {die "truncated file";}
+
+
+ $pos+= ($len +3) & ~3;
+ seek (LOGFILE, $pos, SEEK_SET) or die "truncated file";
+ $i++;
+ }
+
+ close (LOGFILE);
+
+ if ($VerboseMode)
+ {
+ print "*** Processes ***\n";
+ for $id ( keys %ProcessNames )
+ {
+ printf ("process %08X ProcessName %s\n", $id, $ProcessNames{$id});
+ }
+ print "*** Thread ***\n";
+ for $id ( keys %ThreadNames )
+ {
+ printf ("thread %08X ThreadName %s::%X\n", $id, $ThreadNames{$id}, $ThreadIds{$id});
+ }
+ }
+
+ }
+
+
+sub ReadSingleRecord
+ {
+ ($fh, $data, $dataLen, $recordLen, $category, $subCategory, $multipartFlags, $extraN, $totalLen, $offset, $RawMode) = @_;
+
+ my $hdr;
+ my $flags;
+ my $header2;
+ my $timestamp;
+ my $timestamp2;
+ my $contextId;
+ my $programConter;
+
+ my $recordOffset = 0;
+
+ $timestampLast;
+ my $timestampDelta = 0;
+
+ my $bytesRead = read($fh, $hdr, 4);
+
+
+ if ($bytesRead < 4)
+ {return -1;}
+
+ ($$recordLen,$flags,$$category,$$subCategory) = unpack("CCCC", $hdr);
+ $$dataLen = $$recordLen-4;
+
+ if ($flags & $EHeader2Present)
+ {$$multipartFlags = (ReadDword($fh) & $EMultipartFlagMask); $$dataLen-= 4}
+ else
+ {$$multipartFlags = 0;}
+ if ($flags & $ETimestampPresent)
+ {$timestamp = ReadDword($fh); $$dataLen-= 4;}
+ if ($flags & $ETimestamp2Present)
+ {$timestamp2 = ReadDword($fh); $$dataLen-= 4;}
+ if ($flags & $EContextIdPresent)
+ {$contextId = ReadDword($fh); $$dataLen-= 4;}
+ if ($flags & $EPcPresent)
+ {$programConter = ReadDword($fh); $$dataLen-= 4;}
+ if ($flags & $EExtraPresent)
+ {$$extraN = ReadDword($fh); $$dataLen-= 4;}
+ if ($$multipartFlags != 0)
+ {
+ $$totalLen = ReadDword($fh); $$dataLen-= 4;
+ if ($$multipartFlags == $EMultipartMiddle || $$multipartFlags == $EMultipartLast)
+ {$$offset = ReadDword($fh); $$totalLen-= 4; $$dataLen-= 4;}
+ }
+
+ $timestampDelta = $timestamp - $timestampLast;
+ $timestampLast = $timestamp;
+
+ read($fh, $$data, ($$dataLen + 3) & ~3);
+
+
+ if ($RawMode || $$multipartFlags == $EMultipartFirst || $$multipartFlags == 0)
+ {
+ # print header len (col #1)
+ if ($PrintFlagHdrLen){printf ("0x%02X, ", $$recordLen);}
+
+ # print header flags (col #2)
+ if ($PrintFlagHdrFlags)
+ {
+ printf ("%02X ", $flags);
+ if ($flags & $EHeader2Present) {printf "EHeader2Present ";}
+ if ($flags & $ETimestampPresent) {printf "ETimestampPresent ";}
+ if ($flags & $ETimestamp2Present) {printf "ETimestamp2Present ";}
+ if ($flags & $EContextIdPresent) {printf "EContextIdPresent ";}
+ if ($flags & $EPcPresent) {printf "EPcPresent ";}
+ if ($$multipartFlags != 0)
+ {
+ printf "EExtraPresent ";
+ if ($$multipartFlags == $EMultipartFirst) {print "EMultipartFirst ";}
+ elsif ($$multipartFlags == $EMultipartMiddle) {print "EMultipartMiddle ";}
+ elsif ($$multipartFlags == $EMultipartLast) {print "EMultipartLast ";}
+ printf ("ExtraN(0x%08X) ", $$extraN);
+ }
+ if ($flags & $ERecordTruncated) {printf "ERecordTruncated ";}
+ if ($flags & $EMissingRecord) {printf "EMissingRecord ";}
+ print ",";
+ }
+
+ # print category (col #3)
+ printf "(%d;%d) $categoryString , ", $$category, $$subCategory;
+
+ # print timestamp(s) (col #4)
+ printf "0x";
+ if (defined $timestamp2) {printf "%08X : ", $timestamp2;}
+ printf "%08X", $timestamp;
+ printf ", ";;
+
+ # print timestamp delta (col #5)
+ printf "0x%08X, ", $timestampDelta;
+
+ # print context Id (col #6)
+ if (!$RawMode && defined $ThreadNames{$contextId})
+ {
+ printf ("%s::%X, ", $ThreadNames{$contextId}, $ThreadIds{$contextId});
+ }
+ else
+ {
+ if ((($contextId & $EContextIdMask) == $EContextIdThread) || $RawMode)
+ {printf "0x%08X, ", $contextId;}
+ elsif (($contextId & $EContextIdMask) == $EContextIdFIQ)
+ {printf "FIQ, ";}
+ elsif (($contextId & $EContextIdMask) == $EContextIdIRQ)
+ {printf "IRQ, ";}
+ elsif (($contextId & $EContextIdMask) == $EContextIdIDFC)
+ {printf "IDFC, ";}
+ }
+
+ # print Program Counter (col #7)
+ printf "0x%08X, ", $programConter;
+ }
+
+
+
+
+#########################################################
+# my $hex;
+# for (my $i=0; $i < $$dataLen; $i+=4)
+# {
+# $hex.= sprintf ("%08X ", unpack("V", substr($$data, $i, 4)));
+# }
+# printf "\nadding [$hex]\n";
+#########################################################
+ return $bytesRead
+ }
+
+
+sub ReadRecord
+ {
+ ($fh, $recordPos, $recordData, $category, $subCategory, $multipartFlags, $RawMode) = @_;
+# printf "CurrentPos %08X\n", $pos;
+
+
+
+ seek ($fh, $$recordPos, SEEK_SET) or die "truncated file";
+ my $recordLen;
+ my $extraN;
+ my $totalLen;
+ my $offset;
+ my $dataLen;
+ my $data;
+ my $bytesRead;
+
+
+ $bytesRead = ReadSingleRecord($fh, \$data, \$dataLen, \$recordLen, \$$category, \$$subCategory, \$$multipartFlags, \$extraN, \$totalLen, \$offset, $RawMode);
+
+ if ($bytesRead == -1) # eof ?
+ {return -1; }
+ $$recordPos+= ($recordLen +3) & ~3;
+
+ $$recordData = $data;
+ $offset = $dataLen;
+
+ $offset-= 4; # subtract 4 bytes for UID ?????????
+
+ if ($RawMode || $$multipartFlags != $EMultipartFirst)
+ {return $dataLen;}
+
+ $pos = $$recordPos;
+
+ while (1)
+ {
+
+ # find next record, i.e. look for a record which matches $extraN
+
+ seek ($fh, $pos, SEEK_SET) or die "truncated file";
+
+ my $recordLen;
+
+ my $category;
+ my $subCategory;
+ my $multipartFlags;
+ my $currentExtraN;
+ my $currentOffset;
+
+ my $totalLen;
+ my $currentDataLen;
+ my $data;
+ $bytesRead = ReadSingleRecord($fh, \$data, \$currentDataLen, \$recordLen, \$category, \$subCategory, \$multipartFlags, \$currentExtraN, \$totalLen, \$currentOffset, $RawMode);
+ if ($bytesRead == -1) # eof ?
+ {return -1; }
+ $pos+= ($recordLen +3) & ~3;
+
+# printf "\npos %08X, Seaching for (extra %08X, offset %08X), found (extra %08X, offset %08X)\n",
+# $pos, $extraN, $offset, $currentExtraN, $currentOffset;
+
+ if ($currentExtraN == $extraN && $currentOffset == $offset)
+ {
+ $$recordData.= $data;
+ $offset+= $currentDataLen;
+ $dataLen+= $currentDataLen;
+ }
+
+ if ($multipartFlags == $EMultipartLast)
+ {last;}
+ }
+
+ return $dataLen;
+ }
+
+sub ReadDword {
+ (my $fh) = @_;
+ my $buffer;
+
+ $bytesRead = read($fh, $buffer, 4);
+ if ($bytesRead < 4) {die "truncated file";}
+
+ my $dword = unpack("V", $buffer);
+
+ return $dword
+ };
+
+sub ReadByte {
+ (my $fh) = @_;
+ my $buffer;
+
+ $bytesRead = read($fh, $buffer, 1);
+ if ($bytesRead < 1) {die "truncated file";}
+
+ my $byte = unpack("C", $buffer);
+
+ return $byte
+ };
+
+
+
+sub PrintFormatTables($)
+ {
+ my ($formatTables) = @_;
+
+ for $tableIndex ( sort keys %$formatTables )
+ {
+ printf ("SYMTraceFormatCategory %08X:\n", $tableIndex);
+ for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
+ {
+ printf ("%08X => %s\n", $formatId, $$formatTables{$tableIndex}{$formatId});
+ }
+ print "\n";
+ }
+ }
+
+
+
+sub OutputSawDictionary($)
+ {
+ my ($formatTables) = @_;
+
+
+ # SAW enums
+ $EFieldTypeHexDump = 0;
+ $EFieldTypeHex = 1;
+ $EFieldTypeDecimal = 2;
+ $EFieldTypeStringToEnd = 3;
+ $EFieldTypeNullTerminatedString = 4;
+ $EFieldTypeHexDumpToEnd = 5;
+ $EFieldTypeUnicodeToEnd = 6;
+ $EFieldTypeNullTerminatedUnicode = 7;
+ $EFieldTypeCountedUnicode = 8;
+ $EFieldTypeCountedHexDump = 9;
+ $EFieldTypeCountedString = 10;
+
+ my $moduleIds; # string containg all UIDs separared by semi-colons
+
+ for $tableIndex ( sort keys %$formatTables )
+ {
+ if ($tableIndex < 256)
+ {
+ next;
+ }
+ $moduleIds.= sprintf ("%08X;", $tableIndex);
+
+ printf ("MODULEID_%08X_DESC=\n", $tableIndex);
+ printf ("MODULEID_%08X_NAME=%08X\n", $tableIndex, $tableIndex);
+
+ my $formatIds;
+ $formatIds = sprintf ("MODULEID_%08X_FORMATIDS=", $tableIndex);
+
+ for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
+ {
+ $formatIds.= sprintf ("%d;", $formatId);
+ }
+ printf ("$formatIds\n");
+
+
+ for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
+ {
+ my $fieldCount = 0;
+ my $formatString = $$formatTables{$tableIndex}{$formatId};
+
+#printf ("formatString = (%s)\n", $formatString);
+
+ # format name is the first format string up until the first space or '%' character or end-of line ...
+ $formatString=~ m/^[^%\s]*/;
+ my $formatName = $&;
+
+ # thow the format name away
+ $formatString = $';
+
+ # strip the leading space
+ $formatString=~ s/\s*//;
+
+ printf ("MODULEID_%08X_FORMATID_%d_NAME=%s\n", $tableIndex, $formatId, $formatName);
+#printf ("MODULEID_%08X_FORMATID_%d_DESC=\n", $tableIndex, $formatId);
+
+ my $lenFormatString = length($formatString);
+
+ my $formattedText;
+ my $fieldType = $EFieldTypeHex;
+ my $fieldLen = 0;
+ while (length($formatString))
+ {
+ my $c = (substr ($formatString, 0, 1));
+#print ("[$formatString][$c]\n");
+ $formatString=~ s/.//; # strip the leading space
+ if ($c eq "%")
+ {
+#print "found %\n";
+ my $fieldLenSpecified = 0;
+ $c = (substr ($formatString, 0, 1));
+ $formatString=~ s/.//; # discard char
+#print "c2=$c\n";
+ if ($c eq "%")
+ {
+ $formattedText.= substr ($formatString, 0, 1);
+ next;
+ }
+ if ($c eq "*") ## take length from buffer
+ {
+ $fieldLenSpecified = 1;
+ $c = (substr ($formatString, 0, 1));
+ $formatString=~ s/.//; # discard char
+ }
+ if (lc $c eq "x" || $c eq "h")
+ {
+ ## deal wilth $fieldLenSpecified
+ if ($fieldLenSpecified)
+ {
+ $fieldType = $EFieldTypeCountedHexDump;
+ $fieldLen = 0;
+ }
+ else
+ {
+ $fieldType = $EFieldTypeHex;
+ $fieldLen = 4;
+ }
+ }
+ elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "d")
+ {
+ $formatString=~ s/.//; # discard char
+ $fieldType = $EFieldTypeDecimal;
+ $fieldLen = 8;
+ }
+ elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "x")
+ {
+ $formatString=~ s/.//; # discard char
+ $fieldType = $EFieldTypeHex;
+ $fieldLen = 8;
+ }
+ elsif (lc $c eq "d")
+ {
+ $fieldType = $EFieldTypeDecimal;
+ $fieldLen = 4;
+ }
+ elsif ($c eq "s")
+ {
+ ## deal wilth $fieldLenSpecified
+ if ($fieldLenSpecified)
+ {
+ $fieldType = $EFieldTypeCountedString;
+ $fieldLen = 0;
+ }
+ else
+ {
+ $fieldType = $EFieldTypeStringToEnd;
+ $fieldLen = 0;
+ }
+ }
+ elsif ($c eq "S")
+ {
+ ## deal wilth $fieldLenSpecified
+ if ($fieldLenSpecified)
+ {
+ $fieldType = $EFieldTypeCountedUnicode;
+ $fieldLen = 0;
+ }
+ else
+ {
+ $fieldType = EFieldTypeUnicodeToEnd;
+ $fieldLen = 0;
+ }
+ }
+ elsif ($c eq "c")
+ {
+ $fieldType = $EFieldTypeHex;
+ $fieldLen = 1;
+ }
+ printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_NAME=%s\n", $tableIndex, $formatId, $fieldCount, $formattedText);
+ printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_TYPE=%s\n", $tableIndex, $formatId, $fieldCount, $fieldType);
+ if ($fieldLen > 0)
+ {printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_LENGTH=%s\n", $tableIndex, $formatId, $fieldCount, $fieldLen);}
+ $fieldCount++;
+ $formattedText="";
+
+ $formatString=~ s/\s//; # strip the leading space
+ }
+ else
+ {
+# if ($c eq ":") {$formattedText.= '\\'; }
+ $formattedText.= $c;
+ }
+ }
+ printf ("MODULEID_%08X_FORMATID_%d_FIELDS=%d\n", $tableIndex, $formatId, $fieldCount);
+
+ }
+ print "MODULEIDS=$moduleIds\n";
+ }
+ }
+
+
+
+
+
+
+
+
+sub H2Trace($$)
+{
+ %basictypes = (
+ TInt8 => 1,
+ TUint8 => 1,
+ TInt16 => 2,
+ TUint16 => 2,
+ TInt32 => 4,
+ TUint32 => 4,
+ TInt => 4,
+ TUint => 4,
+ TBool => 4,
+ TInt64 => 8,
+ TUint64 => 8,
+ TLinAddr => 4,
+ TVersion => 4,
+ TPde => 4,
+ TPte => 4,
+ TProcessPriority => 4,
+ TFormatId => 2,
+ );
+
+ if (scalar(@_)!= 2) {
+ die "perl h2trace.pl <input.h>\n";
+ }
+ my ($infile, $filescope) = @_;
+
+ if ($VerboseMode)
+ {print "\nOpening $infile\n";}
+
+ open IN, $infile or die "Can't open $infile for input\n";
+ my $in;
+ while (<IN>) {
+ $in.=$_;
+ }
+ close IN;
+
+ # First remove any backslash-newline combinations
+ $in =~ s/\\\n//gms;
+
+ # Remove any character constants
+ $in =~ s/\'(.?(${0})*?)\'//gms;
+
+ # Strip comments beginning with //
+ $in =~ s/\/\/(.*?)\n/\n/gms; #//(.*?)\n
+
+ # Strip comments (/* */) but leave doxygen comments (/** */)
+ $in =~ s/\/\*[^*](.*?)\*\//\n/gms; #/*(.*?)*/
+
+
+ # Collapse whitespace into a single space or newline
+ $in =~ s/\t/\ /gms;
+ $in =~ s/\r/\ /gms;
+
+ # Tokenize on non-identifier characters
+ my @tokens0 = split(/(\W)/,$in);
+ my @tokens;
+ my $inString = 0;
+ my $inComment = 0;
+ my $string;
+ foreach $t (@tokens0) {
+ next if ($t eq "");
+ next if (!$inString && ($t eq " " or $t eq ""));
+ if ($inComment == 0)
+ {
+ if ($t eq "/")
+ {$inComment = 1;}
+ }
+ elsif ($inComment == 1)
+ {
+ if ($t eq "*")
+ {$inComment = 2;}
+ else
+ {$inComment = 0;}
+ }
+ elsif ($inComment == 2)
+ {
+ if ($t eq "*")
+ {$inComment = 3;}
+ }
+ elsif ($inComment == 3)
+ {
+ if ($t eq "/")
+ {
+ $inComment = 0;
+ # if we were in a string, need to push previous '*'
+ if ($inString)
+ {
+ push @tokens, "*";
+ }
+ $inString = 0; # end of comment aborts a string
+ $string = "";
+ }
+ else
+ {$inComment = 2;}
+ }
+
+ if ($t eq "\"")
+ {
+ if (!$inString)
+ {
+ $inString=1;
+ next;
+ }
+ else
+ {
+ $inString=0;
+ $t = $string;
+ $string = "";
+# if ($VerboseMode) {print "string : [$t]\n"; }
+ }
+ }
+
+ if ($inString)
+ {
+ $string.= $t;
+ next;
+ }
+ push @tokens, $t;
+ }
+
+ my $CurrentTraceFormatString;
+ my $CurrentTraceFormatCategory;
+ # format Key as specified by the @TraceFormatCategory tag is either the current category
+ # or the current UID
+ my $CurrentFormatTableKey;
+
+
+ my $line=1;
+ parse_scope($filescope, \@tokens, \$line);
+
+ #print $in;
+ #print join (" ", @tokens);
+} # end of H2Trace
+
+
+
+ sub parse_scope($$$) {
+ my ($scope, $tokens, $line) = @_;
+ my $state = 1;
+
+ my @classes;
+ my $curr_offset=0;
+ my $overall_align=0;
+# print ">parse_scope $scope->{name}\n";
+
+ while (scalar(@$tokens))
+ {
+ my $t = shift @$tokens;
+# printf "t: [$t] [$$line]\n";
+ if (!defined ($t)) {
+ printf "undefined !";
+ next;
+ }
+ if ($state>=-1 and $t eq "\n") {
+ ++$$line;
+ $state=1;
+ next;
+ } elsif ($state==-1 and $t ne "\n") {
+ next;
+ } elsif ($state==-2 and $t ne ';') {
+ next;
+ }
+
+ if ($state>0 and $t eq '#') {
+ $t = shift @$tokens;
+ if ($t eq 'define') {
+ my $ident = shift @$tokens;
+ my $defn = shift @$tokens;
+ if ($defn ne '(') { # don't do macros with parameters
+# print "MACRO: $ident :== $defn\n";
+ $macros{$ident} = $defn;
+ }
+ }
+ $state=-1; # skip to next line
+ next;
+ }
+
+
+ if (parse_doxygen($scope,$tokens, $line, $t) == 1)
+ {next;}
+
+ if ($t eq "namespace" ) {
+ $state=0;
+ my %cl;
+ $cl{specifier}=$t;
+ $cl{scope}=$scope;
+ $cl{values}=$scope->{values};
+ $cl{members}=\$scope->{members};
+ $cl{typedefs}=\$scope->{typedefs};
+ $cl{FormatTables}=$scope->{FormatTables};
+ $cl{formatStrings} =$scope->{formatStrings};
+ $cl{formatCategories} =$scope->{formatCategories};
+
+ my $new_namespace = \%cl;
+ my $n = get_token($scope,$tokens,$line);
+ if ($n !~ /\w+/) {
+ warn "Unnamed $t not supported at line $$line\n";
+ return;
+ }
+ $new_namespace->{name}=$n;
+ my @class_match = grep {$_->{name} eq $n} @classes;
+ my $exists = scalar(@class_match);
+ my $b = get_token($scope,$tokens,$line);
+ if ($b eq ':') {
+ die "Inheritance not supported at line $$line\n";
+ } elsif ($b eq ';') {
+ # forward declaration
+ push @classes, $new_namespace unless ($exists);
+ next;
+ } elsif ($b ne '{') {
+ warn "Syntax error#1 at line $$line\n";
+ return;
+ }
+ if ($exists) {
+ $new_namespace = $class_match[0];
+ if ($new_namespace->{complete}) {
+ warn "Duplicate definition of $cl{specifier} $n\n";
+ }
+ }
+ push @classes, $new_namespace unless ($exists);
+ parse_scope($new_namespace, $tokens, $line);
+ next;
+ }
+
+ if ($t eq "struct" or $t eq "class" or $t eq "NONSHARABLE_CLASS") {
+ next if ($state==0);
+ $state=0;
+ my %cl;
+ $cl{specifier}=$t;
+ $cl{scope}=$scope;
+ my @members;
+ my @typedefs;
+ $cl{members}=\@members;
+ $cl{typedefs}=\@typedefs;
+ $cl{FormatTables}=$scope->{FormatTables};
+ my $new_class = \%cl;
+ my $n;
+
+ if ($t eq "NONSHARABLE_CLASS")
+ {
+ my $b = get_token($scope,$tokens,$line);
+ if ($b !~ /\(/) {die "Syntax error at line $$line\n";}
+ $n = get_token($scope,$tokens,$line);
+ $b = get_token($scope,$tokens,$line);
+ if ($b !~ /\)/) {die "Syntax error at line $$line\n";}
+ }
+ else
+ {
+ $n = get_token($scope,$tokens,$line);
+ }
+
+
+ if ($n !~ /\w+/) {
+ warn "Unnamed $t not supported at line $$line\n";
+ return;
+ }
+ $new_class->{name}=$n;
+ my @class_match = grep {$_->{name} eq $n} @classes;
+ my $exists = scalar(@class_match);
+ my $b = get_token($scope,$tokens,$line);
+ #skip inheritance etc until we get to a '{' or \ ';'
+ while ($b ne '{' && $b ne ';')
+ {
+ $b = get_token($scope,$tokens,$line);
+ die "Syntax error#2 at line $$line\n" if (!defined $b);
+ }
+ if ($b eq ';') {
+ # forward declaration
+ push @classes, $new_class unless ($exists);
+ next;
+ }
+ if ($exists) {
+ $new_class = $class_match[0];
+ if ($new_class->{complete}) {
+ warn "Duplicate definition of $cl{specifier} $n\n";
+ }
+ }
+ push @classes, $new_class unless ($exists);
+ parse_scope($new_class, $tokens, $line);
+ next;
+ } elsif ($t eq "enum") {
+ $state=0;
+ my $n = get_token($scope,$tokens,$line);
+ my $name="";
+ if ($n =~ /\w+/) {
+ $name = $n;
+ $n = get_token($scope,$tokens,$line);
+ }
+ push @enums, $name;
+ if ($n ne '{') {
+ die "Syntax error#4 at line $$line\n";
+ }
+ parse_enum($scope, $tokens, $line, $name);
+ next;
+ } elsif ($t eq '}') {
+ $state=0;
+ if ($scope->{scope}) {
+ if ($scope->{specifier} eq "namespace")
+ {
+ $scope->{complete}=1;
+# print "Scope completed\n";
+ last;
+ }
+ $t = get_token($scope,$tokens,$line);
+ # skip to next ';'
+ while (defined ($t) and $t ne ';')
+ {$t = get_token($scope,$tokens,$line);}
+ die "Syntax error#5 at line $$line\n" if ($t ne ';');
+ $scope->{complete}=1;
+# print "Scope completed\n";
+ last;
+ }
+ warn "Syntax error#5 at line $$line\n";
+ return;
+ }
+ $state=0;
+ if ($scope->{scope}) {
+ if ($t eq "public" or $t eq "private" or $t eq "protected") {
+ if (shift (@$tokens) eq ':') {
+ next; # ignore access specifiers
+ }
+ die "Syntax error#6 at line $$line\n";
+ }
+ }
+ unshift @$tokens, $t;
+
+ my @currdecl = parse_decl_def($scope, $tokens, $line);
+# print scalar (@currdecl), "\n";
+ if ($t eq 'static') {
+ next; # skip static members
+ }
+ my $typedef;
+ if ($t eq 'typedef') {
+# print "TYPEDEF\n";
+ $typedef = 1;
+ $t = shift @currdecl;
+ $t = $currdecl[0];
+ } else {
+# print "NOT TYPEDEF\n";
+ $typedef = 0;
+ }
+# print "$currdecl[0]\n";
+ next if (scalar(@currdecl)==0);
+
+ if ($t eq "const") {
+ # check for constant declaration
+# print "CONST $currdecl[1] $currdecl[2] $currdecl[3]\n";
+ my $ctype = lookup_type($scope, $currdecl[1]);
+# print "$ctype->{basic} $ctype->{size}\n";
+ if ($ctype->{basic} and $currdecl[2]=~/^\w+$/ and $currdecl[3] eq '=') {
+ if ($typedef!=0) {
+ die "Syntax error#7 at line $$line\n";
+ }
+ shift @currdecl;
+ shift @currdecl;
+ my $type = $ctype->{name};
+ my $name; #### = shift @currdecl;
+
+ if ($scope->{name})
+ {
+ $name = $scope->{name} . "::" . shift @currdecl;
+ }
+ else
+ {
+ $name = shift @currdecl;
+ }
+# printf "[$name,$scope->{name}]";
+ my $size = $ctype->{size};
+ shift @currdecl;
+ my $value = get_constant_expr($scope,\@currdecl,$line);
+ $values{$name} = {type=>$type, size=>$size, value=>$value};
+ next;
+ }
+ }
+
+
+
+ }
+ }
+
+ sub get_token($$$) {
+ my ($scope,$tokenlist,$line) = @_;
+ while (scalar(@$tokenlist)) {
+ my $t = shift @$tokenlist;
+ return $t if (!defined($t));
+ if (parse_doxygen($scope,$tokenlist, $line, $t) == 1)
+ {next;}
+ if ($t !~ /^[\s]*$/)
+ {
+ if ($$tokenlist[0] eq ":" and $$tokenlist[1] eq ":")
+ {
+ $t.= shift @$tokenlist;
+ $t.= shift @$tokenlist;
+ $t.= shift @$tokenlist;
+# print "Colon-separated token";
+ }
+ return $t
+ }
+ ++$$line;
+ }
+ return undef;
+ }
+
+ sub skip_qualifiers($) {
+ my ($tokens) = @_;
+ my $f=0;
+ my %quals = (
+ EXPORT_C => 1,
+ IMPORT_C => 1,
+ inline => 1,
+ virtual => 0,
+ const => 0,
+ volatile => 0,
+ static => 0,
+ extern => 0,
+ LOCAL_C => 0,
+ LOCAL_D => 0,
+ GLDEF_C => 0,
+ GLREF_C => 0,
+ GLDEF_D => 0,
+ GLREF_D => 0
+ );
+ for (;;) {
+ my $t = $$tokens[0];
+ my $q = $quals{$t};
+ last unless (defined ($q));
+ $f |= $q;
+ shift @$tokens;
+ }
+ return $f;
+ }
+
+ sub parse_indirection($) {
+ my ($tokens) = @_;
+ my $level = 0;
+ for (;;) {
+ my $t = $$tokens[0];
+ if ($t eq '*') {
+ ++$level;
+ shift @$tokens;
+ next;
+ }
+ last if ($t ne "const" and $t ne "volatile");
+ shift @$tokens;
+ }
+ return $level;
+ }
+
+ sub get_operand($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $t = get_token($scope,$tokens,$line);
+ if ($t eq '-') {
+ my $x = get_operand($scope,$tokens,$line);
+ return -$x;
+ } elsif ($t eq '+') {
+ my $x = get_operand($scope,$tokens,$line);
+ return $x;
+ } elsif ($t eq '~') {
+ my $x = get_operand($scope,$tokens,$line);
+ return ~$x;
+ } elsif ($t eq '!') {
+ my $x = get_operand($scope,$tokens,$line);
+ return $x ? 0 : 1;
+ } elsif ($t eq '(') {
+ my $x = get_constant_expr($scope,$tokens,$line);
+ my $t = get_token($scope,$tokens,$line);
+ if ($t ne ')') {
+ warn "Missing ) at line $$line\n";
+ return undefined;
+ }
+ return $x;
+ } elsif ($t eq "sizeof") {
+ my $ident = get_token($scope,$tokens,$line);
+ if ($ident eq '(') {
+ $ident = get_token($scope,$tokens,$line);
+ my $cb = get_token($scope,$tokens,$line);
+ if ($cb ne ')') {
+ warn "Bad sizeof() syntax at line $$line\n";
+ return undefined;
+ }
+ }
+ $ident = look_through_macros($ident);
+ if ($ident !~ /^\w+$/) {
+ warn "Bad sizeof() syntax at line $$line\n";
+ return undefined;
+ }
+ my $type = lookup_type($scope, $ident);
+ if (!defined $type) {
+ warn "Unrecognised type $ident at line $$line\n";
+ return undefined;
+ }
+ if ($type->{basic}) {
+ return $type->{size};
+ } elsif ($type->{enum}) {
+ return 4;
+ } elsif ($type->{ptr}) {
+ return 4;
+ } elsif ($type->{fptr}) {
+ return 4;
+ }
+ my $al = $type->{class}->{align};
+ my $sz = $type->{class}->{size};
+ return ($sz+$al-1)&~($al-1);
+ }
+ $t = look_through_macros($t);
+ if ($t =~ /^0x/i) {
+ return oct($t);
+ } elsif ($t =~ /^\d/) {
+ return $t;
+ } elsif ($t =~ /^\w+$/) {
+ my $x = lookup_value($scope,$t);
+# die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
+ if (!defined($x)) {
+ print "Unrecognised identifier '$t' at line $$line\n" ;
+ }
+ return $x;
+ } elsif ($t =~ /^\w+::\w+$/) {
+ my $x = lookup_value($scope,$t);
+# die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
+ if (!defined($x)) {
+ print "Unrecognised identifier '$t' at line $$line\n" ;
+ }
+ return $x;
+ } else {
+ warn "Syntax error#10 at line $$line\n";
+ return undefined;
+ }
+ }
+
+ sub look_through_macros($) {
+ my ($ident) = @_;
+ while ($ident and $macros{$ident}) {
+ $ident = $macros{$ident};
+ }
+ return $ident;
+ }
+
+ sub lookup_value($$) {
+ my ($scope,$ident) = @_;
+ while ($scope) {
+ my $vl = $scope->{values};
+ if (defined($vl->{$ident})) {
+ return $vl->{$ident}->{value};
+ }
+ $scope = $scope->{scope};
+ }
+ return undef();
+ }
+
+ sub lookup_type($$) {
+ my ($scope,$ident) = @_;
+ if ($basictypes{$ident}) {
+ return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
+ }
+ while ($scope) {
+ if ($basictypes{$ident}) {
+ return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
+ }
+ my $el = $scope->{enums};
+ my $cl = $scope->{classes};
+ my $td = $scope->{typedefs};
+ if (grep {$_ eq $ident} @$el) {
+ return {scope=>$scope, enum=>1, name=>$ident, size=>4 };
+ }
+ my @match_class = (grep {$_->{name} eq $ident} @$cl);
+ if (scalar(@match_class)) {
+ return {scope=>$scope, class=>$match_class[0]};
+ }
+ my @match_td = (grep {$_->{name} eq $ident} @$td);
+ if (scalar(@match_td)) {
+ my $tdr = $match_td[0];
+ my $cat = $tdr->{category};
+ if ($cat eq 'basic' or $cat eq 'enum' or $cat eq 'class') {
+ $ident = $tdr->{alias};
+ next;
+ } else {
+ return { scope=>$scope, $cat=>1, $size=>$tdr->{size} };
+ }
+ }
+ $scope = $scope->{scope};
+ }
+ return undef();
+ }
+
+ sub get_mult_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_operand($scope,$tokens,$line);
+ my $t;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '*') {
+ my $y = get_operand($scope,$tokens,$line);
+ $x = $x * $y;
+ } elsif ($t eq '/') {
+ my $y = get_operand($scope,$tokens,$line);
+ if ($y != 0)
+ {$x = int($x / $y);}
+ } elsif ($t eq '%') {
+ my $y = get_operand($scope,$tokens,$line);
+ if ($y != 0)
+ {$x = int($x % $y);}
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_add_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_mult_expr($scope,$tokens,$line);
+ my $t;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '+') {
+ my $y = get_mult_expr($scope,$tokens,$line);
+ $x = $x + $y;
+ } elsif ($t eq '-') {
+ my $y = get_mult_expr($scope,$tokens,$line);
+ $x = $x - $y;
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_shift_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_add_expr($scope,$tokens,$line);
+ my $t, $t2;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '<' or $t eq '>') {
+ $t2 = get_token($scope,$tokens,$line);
+ if ($t2 ne $t) {
+ unshift @$tokens, $t2;
+ last;
+ }
+ }
+ if ($t eq '<') {
+ my $y = get_add_expr($scope,$tokens,$line);
+ $x = $x << $y;
+ } elsif ($t eq '>') {
+ my $y = get_add_expr($scope,$tokens,$line);
+ $x = $x >> $y;
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_and_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_shift_expr($scope,$tokens,$line);
+ my $t;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '&') {
+ my $y = get_shift_expr($scope,$tokens,$line);
+ $x = $x & $y;
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_xor_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_and_expr($scope,$tokens,$line);
+ my $t;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '^') {
+ my $y = get_and_expr($scope,$tokens,$line);
+ $x = $x ^ $y;
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_ior_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_xor_expr($scope,$tokens,$line);
+ my $t;
+ for (;;) {
+ $t = get_token($scope,$tokens,$line);
+ if ($t eq '|') {
+ my $y = get_xor_expr($scope,$tokens,$line);
+ $x = $x | $y;
+ } else {
+ last;
+ }
+ }
+ unshift @$tokens, $t;
+ return $x;
+ }
+
+ sub get_constant_expr($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $x = get_ior_expr($scope,$tokens,$line);
+ return $x;
+ }
+
+ sub parse_enum($$$$) {
+ my ($scope,$tokens,$line,$enum_name) = @_;
+ my $vl = $scope->{values};
+ my $fstr = $scope->{formatStrings};
+ my $fcat = $scope->{formatCategories};
+ my $fmtTable = $scope->{FormatTables};
+
+ my $x = 0;
+ for (;;) {
+ my $t = get_token($scope,$tokens,$line);
+ last if ($t eq '}');
+ if (!defined($t)) {
+ die "Unexpected end of file #2 at line $$line\n";
+ }
+
+ if ($t eq '#') {
+ next;
+ }
+
+ if ($t !~ /^\w+$/) {
+ warn "Syntax error#11 at line $$line\n";
+ next;
+ }
+
+ if ($scope->{name})
+ {
+ $t = $scope->{name} . "::" . $t;
+ }
+
+ if (defined($vl->{$t})) {
+ warn "Duplicate identifier [$t] at line $$line\n";
+ }
+ my $t2 = get_token($scope,$tokens,$line);
+ if ($t2 eq ',') {
+ $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
+ $fstr->{$t} = $CurrentTraceFormatString;
+ $fcat->{$t} = $CurrentTraceFormatCategory;
+ if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
+ { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
+ undef $CurrentTraceFormatString;
+ ++$x;
+ } elsif ($t2 eq '}') {
+ $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
+ $fstr->{$t} = $CurrentTraceFormatString;
+ $fcat->{$t} = $CurrentTraceFormatCategory;
+ if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
+ { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
+ undef $CurrentTraceFormatString;
+ ++$x;
+ last;
+ } elsif ($t2 eq '=') {
+ $x = get_constant_expr($scope, $tokens, $line);
+ $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
+ $fstr->{$t} = $CurrentTraceFormatString;
+ $fcat->{$t} = $CurrentTraceFormatCategory;
+ if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
+ { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
+ undef $CurrentTraceFormatString;
+ ++$x;
+ $t2 = get_token($scope,$tokens,$line);
+ last if ($t2 eq '}');
+ next if ($t2 eq ',');
+ warn "Syntax error#12 at line $$line\n";
+ } else {
+ unshift @$tokens, $t2;
+ }
+ }
+ my $t = get_token($scope,$tokens,$line);
+ if ($t ne ';') {
+ warn "Missing ; at line $$line\n";
+ }
+ }
+
+
+ sub parse_decl_def($$$) {
+ my ($scope,$tokens,$line) = @_;
+ my $level=0;
+ my @decl;
+ while ( scalar(@$tokens) ) {
+ my $t = get_token($scope,$tokens, $line);
+ if ( (!defined ($t) || $t eq ';') and ($level==0)) {
+ return @decl;
+ }
+
+ if ($t eq "static")
+ {
+ next;
+ }
+
+ push @decl, $t;
+ if ($t eq '{') {
+ ++$level;
+ }
+ if ($t eq '}') {
+ if ($level==0) {
+ warn "Syntax error#13 at line $$line\n";
+ unshift @$tokens, $t;
+ return @decl;
+
+ }
+ if (--$level==0) {
+ return (); # end of function definition reached
+ }
+ }
+ }
+ die "Unexpected end of file #3 at line $$line\n";
+ }
+
+ sub dump_scope($) {
+ my ($scope) = @_;
+ my $el = $scope->{enums};
+ my $cl = $scope->{classes};
+ my $vl = $scope->{values};
+ my $fstr = $scope->{formatStrings};
+ my $fcat = $scope->{formatCategories};
+ print "SCOPE: $scope->{name}\n";
+ if (scalar(@$el)) {
+ print "\tenums:\n";
+ foreach (@$el) {
+ print "\t\t$_\n";
+ }
+ }
+ if (scalar(keys(%$vl))) {
+ print "\tvalues:\n";
+ foreach $vname (keys(%$vl)) {
+ my $v = $vl->{$vname};
+ my $x = $v->{value};
+ my $t = $v->{type};
+ my $sz = $v->{size};
+ my $fstring = $fstr->{$vname};
+ my $fcategory = $fcat->{$vname};
+ if ($v->{enum}) {
+ printf ("\t\t$vname\=$x (enum $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory,$fstring);
+ } else {
+ printf ("\t\t$vname\=$x (type $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory, $fstring);
+ }
+ }
+ }
+ if ($scope->{scope}) {
+ my $members = $scope->{members};
+ foreach (@$members) {
+ my $n = $_->{name};
+ my $sz = $_->{size};
+ my $off = $_->{offset};
+ my $spc = $_->{spacing};
+ if (defined $spc) {
+ print "\t$n\[\]\: spacing $spc size $sz offset $off\n";
+ } else {
+ print "\t$n\: size $sz offset $off\n";
+ }
+ }
+ print "\tOverall size : $scope->{size}\n";
+ print "\tOverall align: $scope->{align}\n";
+ }
+ foreach $s (@$cl) {
+ dump_scope($s);
+ }
+ }
+
+
+
+
+ sub parse_doxygen($$$$) {
+ my ($scope,$tokens,$line,$t) = @_;
+
+ if ($t ne "/")
+ {
+ return 0; # not a doxygen comment
+ }
+ if ($t eq "/") {
+ $state=0;
+ my $t2 = shift @$tokens;
+ my $t3 = shift @$tokens;
+
+ if ($t2 ne "*" || $t3 ne "*")
+ {
+ unshift @$tokens, $t3;
+ unshift @$tokens, $t2;
+ return 0; # not a doxygen comment
+ }
+ }
+# printf "doxygen start on line %d\n", $$line;
+ for (;;) {
+ my $t = shift @$tokens;
+ if (!defined($t))
+ {
+ warn "Unexpected end of file #4 at line $$line\n";
+ return
+ }
+
+ if ($t eq "\n"){++$$line };
+
+ if ($t eq '*')
+ {
+ my $t2 = shift @$tokens;
+ last if ($t2 eq '/');
+ unshift @$tokens, $t2;
+ }
+
+ if ($t eq '@')
+ {
+ my $t2 = shift @$tokens;
+ if ($t2 eq 'SYMTraceFormatString')
+ {
+ my $t3 = shift @$tokens;
+# if ($VerboseMode){print "SYMTraceFormatString = [$t3]\n";}
+ $CurrentTraceFormatString = $t3;
+ }
+ if ($t2 eq 'SYMTraceFormatCategory')
+ {
+ $CurrentTraceFormatCategory = get_operand($scope,$tokens,$line);
+# if ($VerboseMode){printf ("SYMTraceFormatCategory = 0x%x\n", $CurrentTraceFormatCategory);}
+ }
+ else
+ {
+ unshift @$tokens, $t2;
+ }
+ }
+
+ }
+# printf ("doxygen end on line %d\n", $$line);
+ return 1; # is a doxygen comment
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+