diff -r 000000000000 -r a41df078684a kerneltest/e32utils/trace/btracevw.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32utils/trace/btracevw.pl Mon Oct 19 15:55:17 2009 +0100 @@ -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 ] []\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 \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.=$_; + } + 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 + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + +