Update contrib.
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 # This component and the accompanying materials are made available
5 # under the terms of the License "Eclipse Public License v1.0"
6 # which accompanies this distribution, and is available
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 # Initial Contributors:
10 # Nokia Corporation - initial contribution.
20 use File::Spec::Functions;
25 my $PrintFlagFilePos = 0;
26 my $PrintFlagHdrLen = 0;
27 my $PrintFlagHdrFlags = 0;
28 my $PrintFlagFormatString = 0;
31 my $FormatIdIsSubCategory = 0;
32 my $OutputSawDictionaryMode = 0;
34 # for the category range 0-191, the format string is indexed by the category & subcategory
39 0 => "ThreadId %h, %s",
44 0 => "ThreadId %h, %s",
47 3 => # EThreadIdentification
49 0 => "ENanoThreadCreate, NThread %x",
50 1 => "ENanoThreadDestroy, NThread %x",
51 2 => "EThreadCreate, NThread %x, DProcess %x, name %s",
52 3 => "EThreadDestroy, NThread %x, DProcess %x, Id %x",
53 4 => "EThreadName, NThread %x, DProcess %x, name %s",
54 5 => "EProcessName, NThread %x, DProcess %x, name %s",
55 6 => "EThreadId, NThread %x, DProcess %x, Id %x",
56 7 => "EProcessCreate, DProcess %x",
57 8 => "EProcessDestroy, DProcess %x",
64 # UTF::KInitialClientFormat => {type=>"TFormatId", size=>2, value=>512}
65 KMaxTUint8 => {type=>"TUint8", size=>1, value=>255},
66 KMaxTUint16 => {type=>"TUint16", size=>2, value=>65535}
71 my %formatStrings; # each enum may have it's own format string
72 my %formatCategories; # each enum may have it's own format category
76 undef $filescope{name};
78 $filescope{typedefs}=\@typedefs;
79 $filescope{members}=\@members;
80 $filescope{values}=\%values;
81 $filescope{macros} = \%macros;
82 $filescope{FormatTables} = \%FormatTables;
84 $filescope{classes} = \@classes;
85 $filescope{enums} = \@enums;
87 $filescope{formatStrings} =\%formatStrings;
88 $filescope{formatCategories} = \%formatCategories;
94 print "BTraceVw.pl \n";
95 print "An unsupported utility which extracts UTrace-style format-strings\n";
96 print "from header files & uses these to decode a BTrace output file\n";
97 print "Syntax : BTraceVw.pl [-v] [-r] [-sd] [-i <IncFilePath>] [<BTrace file>]\n";
98 print "where : -v = verbose mode\n";
99 print " : -r = raw output mode\n";
100 print " : -sd = produce SAW trace viewer dictionary file\n";
101 print " : this file then needs to be merged into the 'com.symbian.analysis.trace.ui.prefs' file\n";
102 print " : located under the carbide workspace directory\n";
105 print "e.g. (this decodes a trace file & produces a comma-separated output file) : \n";
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";
108 print "e.g. (this overwrites the SAW dictioany file) : \n";
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";
117 if ($ARGV[0] eq "-i")
126 find sub { push @incFiles, $File::Find::name if m/\.h$/i;}, $FilePath ;
127 foreach $incFile (@incFiles)
129 H2Trace($incFile, \%filescope);
132 elsif ($ARGV[0] eq "-r")
137 elsif ($ARGV[0] eq "-sd")
139 $OutputSawDictionaryMode = 1;
142 elsif ($ARGV[0] eq "-v")
149 $TraceFileName = "$ARGV[0]";
156 dump_scope(\%filescope);
157 PrintFormatTables(\%FormatTables);
159 if ($OutputSawDictionaryMode)
161 OutputSawDictionary(\%FormatTables);
164 if (defined ($TraceFileName))
166 ReadTraceFile($RawMode);
175 # print "Trace file is $TraceFileName, RawMode $RawMode, VerboseMode $VerboseMode\n\n";
177 open (LOGFILE, "<$TraceFileName") or die "Can't open $TraceFileName: $!\n";
183 # enum TFlags from e32btrace.h
184 $EHeader2Present = 1<<0;
185 $ETimestampPresent = 1<<1;
186 $ETimestamp2Present = 1<<2;
187 $EContextIdPresent = 1<<3;
189 $EExtraPresent = 1<<5;
190 $ERecordTruncated = 1<<6;
191 $EMissingRecord = 1<<7;
193 # enum TFlags2 from e32btrace.h
194 $EMultipartFlagMask = 3<<0;
195 $ECpuIdMask = 0xfff<<20;
197 # enum TMultiPart from e32btrace.h
198 $EMultipartFirst = 1;
199 $EMultipartMiddle = 2;
202 $EMaxBTraceDataArray = 80;
204 # enum TCategory from e32btrace.h
205 $EThreadIdentification = 3;
207 # enum TThreadIdentification from e32btrace.h
213 # Context Id bits from e32btrace.h
214 $EContextIdMask = 0x00000003;
215 $EContextIdThread = 0;
216 $EContextIdFIQ = 0x1;
217 $EContextIdIRQ = 0x2;
218 $EContextIdIDFC = 0x3;
220 # enum TClassificationRange from e32btraceu.h
221 $EAllRangeFirst = 192;
222 $EAllRangeLast = 222;
224 %TCategoryIdToString =
226 0 => "ERDebugPrintf",
228 2 => "EPlatsecPrintf",
229 3 => "EThreadIdentification",
232 6 => "EClientServer",
237 11 => "EThreadPriority",
238 12 => "EPagingMedia",
239 13 => "EKernelMemory",
242 16 => "ERamAllocator",
245 19 => "EResourceManager",
246 20 => "EResourceManagerUs",
248 128 => "EPlatformSpecificFirst",
249 191 => "EPlatformSpecificLast",
250 192 => "ESymbianExtentionsFirst",
261 200 => "ESystemCharacteristicMetrics",
264 253 => "ESymbianExtentionsLast",
275 # print column titles
276 if ($PrintFlagFilePos) {printf "FilePos, ";} # col #0
277 if ($PrintFlagHdrLen) { printf "Len, ";} # col #1
278 if ($PrintFlagHdrFlags) {printf "Flags, "; } # col #2
279 printf "Category, "; # col #3
280 printf "TimeStamp, "; # col #4
281 printf "Delta, "; # col #5
282 printf "context Id, "; # col #6
283 printf "PC, "; # col #7
284 printf "UID, "; # col #8
285 if ($PrintFlagFormatString){printf "Format string, ";} # col #9
286 printf "Formatted text, "; # col #10
292 my $pos = tell (LOGFILE);
294 # print file pos (col #0)
295 if ($PrintFlagFilePos){ printf ("0x%08X, ", $pos);}
299 my $multipartFlags = 0;
304 $recordLen = ReadRecord(LOGFILE, \$pos, \$recordData, \$category, \$subCategory, \$multipartFlags, $RawMode);
305 if ($recordLen == -1)
309 if (!$RawMode && ($multipartFlags == $EMultipartMiddle || $multipartFlags == $EMultipartLast))
312 # print record contents
314 # for (my $i=0; $i < $recordLen; $i+=4)
316 # $buf.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos+$i, 4)));
318 # printf "\n[$buf\n]";
321 # for UTrace "ALL" range, read UID
322 if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast &&
323 (!$RawMode) && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
325 $uid = unpack("V", substr($recordData, $recordPos, 4));
329 $FormatIdIsSubCategory = ($subCategory != 0) ? 1 : 0;
330 if ($FormatIdIsSubCategory)
332 $formatId = $subCategory
336 $formatId = unpack("V", substr($recordData, $recordPos, 4));
343 printf "0x%08X, ", $uid;
348 if ($category >= $EAllRangeFirst && $category <= $EAllRangeLast)
350 $formatString = $FormatTables{$uid}{$formatId};
354 $formatString = $FormatTables{$category}{$subCategory};
359 if ($category == $EThreadIdentification)
361 if ($subCategory == $EProcessName)
363 my $process = unpack("V", substr($recordData, 4, 4));
364 my $processName = substr($recordData, 8, $recordLen - 8);
365 # printf ("\nprocess [%08X] processName [$processName]\n", $process);
366 $ProcessNames{$process} = $processName;
368 elsif ($subCategory == $EThreadCreate || $subCategory == $EThreadName)
370 my $thread = unpack("V", substr($recordData, 0, 4));
371 my $process = unpack("V", substr($recordData, 4, 4));
372 my $threadName = substr($recordData, 8, $recordLen - 8);
373 # printf ("\nprocess [%08X] thread [%08X] threadName [$threadName]\n", $process, $thread, $threadName);
374 $ThreadNames{$thread} = $ProcessNames{$process} . "::" . $threadName;
376 elsif ($subCategory == $EThreadId)
378 my $thread = unpack("V", substr($recordData, 0, 4));
379 my $process = unpack("V", substr($recordData, 4, 4));
380 my $threadId = unpack("V", substr($recordData, 8, 4));
381 # printf ("\nprocess [%08X] thread [%08X] threadId [%08X]\n", $process, $thread, $threadId);
382 $ThreadIds{$thread} = $threadId;
387 # print Format string (col #9)
388 if ($PrintFlagFormatString)
390 my $formatStringWithoutCommas = $formatString;
391 $formatStringWithoutCommas=~ s/,/ /g;
392 printf "%s, ", $formatStringWithoutCommas;
397 my $lenFormatString = length($formatString);
398 if ($lenFormatString && !$RawMode && $multipartFlags != $EMultipartMiddle && $multipartFlags != $EMultipartLast)
400 for (my $i=0; $i<$lenFormatString; $i++)
402 my $c = (substr ($formatString, $i, 1));
408 $c = (substr ($formatString, $i, 1));
411 $formattedText.= substr ($formatString, $i, 1);
414 if ($c eq "*") ## take length from buffer
416 $fieldLen = unpack("V", substr($recordData, $recordPos, 4));
417 if ($fieldLen > $recordLen-$recordPos)
419 $formattedText.= "*** Invalid field length ***";
424 $c = (substr ($formatString, $i, 1));
426 if (lc $c eq "x" || $c eq "h")
428 if (defined $fieldLen)
430 if (($fieldLen & 3) == 0)
432 for (my $i=0; $i< $fieldLen; $i+= 4)
434 $formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $recordPos, 4)));
440 for (my $i=0; $i< $fieldLen; $i++)
442 $formattedText.= sprintf ("%02X ", unpack("C", substr($recordData, $recordPos, 1)));
449 $formattedText.= sprintf ("0x%08X", unpack("V", substr($recordData, $recordPos, 4)));
452 $recordPos = ($recordPos + 3) & ~3;
455 # display "%ld" as hex for now as don't know how to get perl to use or display a 64 decimal value
456 elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "d")
459 my $loWord = unpack("V", substr($recordData, $recordPos, 4));
461 my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
463 $formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
465 elsif (lc $c eq "l" && substr ($formatString, $i+1, 1) eq "x")
468 my $loWord = unpack("V", substr($recordData, $recordPos, 4));
470 my $hiWord = unpack("V", substr($recordData, $recordPos, 4));
472 $formattedText.= sprintf ("0x%X:%08X", $hiWord, $loWord);
476 $formattedText.= sprintf ("%d", unpack("V", substr($recordData, $recordPos, 4)));
478 $recordPos = ($recordPos + 3) & ~3;
483 if (!defined $fieldLen)
484 {$fieldLen = $recordLen - $recordPos;}
485 $formattedText.= substr($recordData, $recordPos, $fieldLen);
486 $recordPos+= $fieldLen;
487 $recordPos = ($recordPos + 3) & ~3;
492 if (!defined $fieldLen)
493 {$fieldLen = $recordLen-$recordPos;}
494 for (my $j=0; $j < $fieldLen; $j+=2)
496 my $byte = unpack("c", substr ($recordData, $recordPos+$j, 1));
497 $formattedText.= sprintf ("%c", $byte);
499 $recordPos+= $fieldLen;
500 $recordPos = ($recordPos + 3) & ~3;
505 my $byte = unpack("c", substr ($recordData, $recordPos, 1));
506 $formattedText.= sprintf ("%c", $byte);
515 else # no format string : print as hex
517 for (my $i=0; $i < $recordLen; $i+=4)
519 $formattedText.= sprintf ("%08X ", unpack("V", substr($recordData, $i, 4)));
521 $recordPos+= $recordLen; $recordLen = 0;
526 # print Formatted text (col #10)
527 $formattedText=~ s/,/;/g;
528 $formattedText=~ s/\r//g;
529 $formattedText=~ s/\n/,/g;
530 printf "%s", $formattedText;
534 if ($len < 0 || $recordLen < 0) {die "truncated file";}
537 $pos+= ($len +3) & ~3;
538 seek (LOGFILE, $pos, SEEK_SET) or die "truncated file";
546 print "*** Processes ***\n";
547 for $id ( keys %ProcessNames )
549 printf ("process %08X ProcessName %s\n", $id, $ProcessNames{$id});
551 print "*** Thread ***\n";
552 for $id ( keys %ThreadNames )
554 printf ("thread %08X ThreadName %s::%X\n", $id, $ThreadNames{$id}, $ThreadIds{$id});
563 ($fh, $data, $dataLen, $recordLen, $category, $subCategory, $multipartFlags, $extraN, $totalLen, $offset, $RawMode) = @_;
573 my $recordOffset = 0;
576 my $timestampDelta = 0;
578 my $bytesRead = read($fh, $hdr, 4);
584 ($$recordLen,$flags,$$category,$$subCategory) = unpack("CCCC", $hdr);
585 $$dataLen = $$recordLen-4;
587 if ($flags & $EHeader2Present)
588 {$$multipartFlags = (ReadDword($fh) & $EMultipartFlagMask); $$dataLen-= 4}
590 {$$multipartFlags = 0;}
591 if ($flags & $ETimestampPresent)
592 {$timestamp = ReadDword($fh); $$dataLen-= 4;}
593 if ($flags & $ETimestamp2Present)
594 {$timestamp2 = ReadDword($fh); $$dataLen-= 4;}
595 if ($flags & $EContextIdPresent)
596 {$contextId = ReadDword($fh); $$dataLen-= 4;}
597 if ($flags & $EPcPresent)
598 {$programConter = ReadDword($fh); $$dataLen-= 4;}
599 if ($flags & $EExtraPresent)
600 {$$extraN = ReadDword($fh); $$dataLen-= 4;}
601 if ($$multipartFlags != 0)
603 $$totalLen = ReadDword($fh); $$dataLen-= 4;
604 if ($$multipartFlags == $EMultipartMiddle || $$multipartFlags == $EMultipartLast)
605 {$$offset = ReadDword($fh); $$totalLen-= 4; $$dataLen-= 4;}
608 $timestampDelta = $timestamp - $timestampLast;
609 $timestampLast = $timestamp;
611 read($fh, $$data, ($$dataLen + 3) & ~3);
614 if ($RawMode || $$multipartFlags == $EMultipartFirst || $$multipartFlags == 0)
616 # print header len (col #1)
617 if ($PrintFlagHdrLen){printf ("0x%02X, ", $$recordLen);}
619 # print header flags (col #2)
620 if ($PrintFlagHdrFlags)
622 printf ("%02X ", $flags);
623 if ($flags & $EHeader2Present) {printf "EHeader2Present ";}
624 if ($flags & $ETimestampPresent) {printf "ETimestampPresent ";}
625 if ($flags & $ETimestamp2Present) {printf "ETimestamp2Present ";}
626 if ($flags & $EContextIdPresent) {printf "EContextIdPresent ";}
627 if ($flags & $EPcPresent) {printf "EPcPresent ";}
628 if ($$multipartFlags != 0)
630 printf "EExtraPresent ";
631 if ($$multipartFlags == $EMultipartFirst) {print "EMultipartFirst ";}
632 elsif ($$multipartFlags == $EMultipartMiddle) {print "EMultipartMiddle ";}
633 elsif ($$multipartFlags == $EMultipartLast) {print "EMultipartLast ";}
634 printf ("ExtraN(0x%08X) ", $$extraN);
636 if ($flags & $ERecordTruncated) {printf "ERecordTruncated ";}
637 if ($flags & $EMissingRecord) {printf "EMissingRecord ";}
641 # print category (col #3)
642 printf "(%d;%d) $categoryString , ", $$category, $$subCategory;
644 # print timestamp(s) (col #4)
646 if (defined $timestamp2) {printf "%08X : ", $timestamp2;}
647 printf "%08X", $timestamp;
650 # print timestamp delta (col #5)
651 printf "0x%08X, ", $timestampDelta;
653 # print context Id (col #6)
654 if (!$RawMode && defined $ThreadNames{$contextId})
656 printf ("%s::%X, ", $ThreadNames{$contextId}, $ThreadIds{$contextId});
660 if ((($contextId & $EContextIdMask) == $EContextIdThread) || $RawMode)
661 {printf "0x%08X, ", $contextId;}
662 elsif (($contextId & $EContextIdMask) == $EContextIdFIQ)
664 elsif (($contextId & $EContextIdMask) == $EContextIdIRQ)
666 elsif (($contextId & $EContextIdMask) == $EContextIdIDFC)
670 # print Program Counter (col #7)
671 printf "0x%08X, ", $programConter;
677 #########################################################
679 # for (my $i=0; $i < $$dataLen; $i+=4)
681 # $hex.= sprintf ("%08X ", unpack("V", substr($$data, $i, 4)));
683 # printf "\nadding [$hex]\n";
684 #########################################################
691 ($fh, $recordPos, $recordData, $category, $subCategory, $multipartFlags, $RawMode) = @_;
692 # printf "CurrentPos %08X\n", $pos;
696 seek ($fh, $$recordPos, SEEK_SET) or die "truncated file";
706 $bytesRead = ReadSingleRecord($fh, \$data, \$dataLen, \$recordLen, \$$category, \$$subCategory, \$$multipartFlags, \$extraN, \$totalLen, \$offset, $RawMode);
708 if ($bytesRead == -1) # eof ?
710 $$recordPos+= ($recordLen +3) & ~3;
712 $$recordData = $data;
715 $offset-= 4; # subtract 4 bytes for UID ?????????
717 if ($RawMode || $$multipartFlags != $EMultipartFirst)
725 # find next record, i.e. look for a record which matches $extraN
727 seek ($fh, $pos, SEEK_SET) or die "truncated file";
740 $bytesRead = ReadSingleRecord($fh, \$data, \$currentDataLen, \$recordLen, \$category, \$subCategory, \$multipartFlags, \$currentExtraN, \$totalLen, \$currentOffset, $RawMode);
741 if ($bytesRead == -1) # eof ?
743 $pos+= ($recordLen +3) & ~3;
745 # printf "\npos %08X, Seaching for (extra %08X, offset %08X), found (extra %08X, offset %08X)\n",
746 # $pos, $extraN, $offset, $currentExtraN, $currentOffset;
748 if ($currentExtraN == $extraN && $currentOffset == $offset)
750 $$recordData.= $data;
751 $offset+= $currentDataLen;
752 $dataLen+= $currentDataLen;
755 if ($multipartFlags == $EMultipartLast)
766 $bytesRead = read($fh, $buffer, 4);
767 if ($bytesRead < 4) {die "truncated file";}
769 my $dword = unpack("V", $buffer);
778 $bytesRead = read($fh, $buffer, 1);
779 if ($bytesRead < 1) {die "truncated file";}
781 my $byte = unpack("C", $buffer);
788 sub PrintFormatTables($)
790 my ($formatTables) = @_;
792 for $tableIndex ( sort keys %$formatTables )
794 printf ("SYMTraceFormatCategory %08X:\n", $tableIndex);
795 for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
797 printf ("%08X => %s\n", $formatId, $$formatTables{$tableIndex}{$formatId});
805 sub OutputSawDictionary($)
807 my ($formatTables) = @_;
811 $EFieldTypeHexDump = 0;
813 $EFieldTypeDecimal = 2;
814 $EFieldTypeStringToEnd = 3;
815 $EFieldTypeNullTerminatedString = 4;
816 $EFieldTypeHexDumpToEnd = 5;
817 $EFieldTypeUnicodeToEnd = 6;
818 $EFieldTypeNullTerminatedUnicode = 7;
819 $EFieldTypeCountedUnicode = 8;
820 $EFieldTypeCountedHexDump = 9;
821 $EFieldTypeCountedString = 10;
823 my $moduleIds; # string containg all UIDs separared by semi-colons
825 for $tableIndex ( sort keys %$formatTables )
827 if ($tableIndex < 256)
831 $moduleIds.= sprintf ("%08X;", $tableIndex);
833 printf ("MODULEID_%08X_DESC=\n", $tableIndex);
834 printf ("MODULEID_%08X_NAME=%08X\n", $tableIndex, $tableIndex);
837 $formatIds = sprintf ("MODULEID_%08X_FORMATIDS=", $tableIndex);
839 for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
841 $formatIds.= sprintf ("%d;", $formatId);
843 printf ("$formatIds\n");
846 for $formatId (sort keys %{ $$formatTables{$tableIndex} } )
849 my $formatString = $$formatTables{$tableIndex}{$formatId};
851 #printf ("formatString = (%s)\n", $formatString);
853 # format name is the first format string up until the first space or '%' character or end-of line ...
854 $formatString=~ m/^[^%\s]*/;
857 # thow the format name away
860 # strip the leading space
861 $formatString=~ s/\s*//;
863 printf ("MODULEID_%08X_FORMATID_%d_NAME=%s\n", $tableIndex, $formatId, $formatName);
864 #printf ("MODULEID_%08X_FORMATID_%d_DESC=\n", $tableIndex, $formatId);
866 my $lenFormatString = length($formatString);
869 my $fieldType = $EFieldTypeHex;
871 while (length($formatString))
873 my $c = (substr ($formatString, 0, 1));
874 #print ("[$formatString][$c]\n");
875 $formatString=~ s/.//; # strip the leading space
879 my $fieldLenSpecified = 0;
880 $c = (substr ($formatString, 0, 1));
881 $formatString=~ s/.//; # discard char
885 $formattedText.= substr ($formatString, 0, 1);
888 if ($c eq "*") ## take length from buffer
890 $fieldLenSpecified = 1;
891 $c = (substr ($formatString, 0, 1));
892 $formatString=~ s/.//; # discard char
894 if (lc $c eq "x" || $c eq "h")
896 ## deal wilth $fieldLenSpecified
897 if ($fieldLenSpecified)
899 $fieldType = $EFieldTypeCountedHexDump;
904 $fieldType = $EFieldTypeHex;
908 elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "d")
910 $formatString=~ s/.//; # discard char
911 $fieldType = $EFieldTypeDecimal;
914 elsif (lc $c eq "l" && substr ($formatString, 0, 1) eq "x")
916 $formatString=~ s/.//; # discard char
917 $fieldType = $EFieldTypeHex;
922 $fieldType = $EFieldTypeDecimal;
927 ## deal wilth $fieldLenSpecified
928 if ($fieldLenSpecified)
930 $fieldType = $EFieldTypeCountedString;
935 $fieldType = $EFieldTypeStringToEnd;
941 ## deal wilth $fieldLenSpecified
942 if ($fieldLenSpecified)
944 $fieldType = $EFieldTypeCountedUnicode;
949 $fieldType = EFieldTypeUnicodeToEnd;
955 $fieldType = $EFieldTypeHex;
958 printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_NAME=%s\n", $tableIndex, $formatId, $fieldCount, $formattedText);
959 printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_TYPE=%s\n", $tableIndex, $formatId, $fieldCount, $fieldType);
961 {printf ("MODULEID_%08X_FORMATID_%d_FIELD_%d_LENGTH=%s\n", $tableIndex, $formatId, $fieldCount, $fieldLen);}
965 $formatString=~ s/\s//; # strip the leading space
969 # if ($c eq ":") {$formattedText.= '\\'; }
973 printf ("MODULEID_%08X_FORMATID_%d_FIELDS=%d\n", $tableIndex, $formatId, $fieldCount);
976 print "MODULEIDS=$moduleIds\n";
1005 TProcessPriority => 4,
1009 if (scalar(@_)!= 2) {
1010 die "perl h2trace.pl <input.h>\n";
1012 my ($infile, $filescope) = @_;
1015 {print "\nOpening $infile\n";}
1017 open IN, $infile or die "Can't open $infile for input\n";
1024 # First remove any backslash-newline combinations
1027 # Remove any character constants
1028 $in =~ s/\'(.?(${0})*?)\'//gms;
1030 # Strip comments beginning with //
1031 $in =~ s/\/\/(.*?)\n/\n/gms; #//(.*?)\n
1033 # Strip comments (/* */) but leave doxygen comments (/** */)
1034 $in =~ s/\/\*[^*](.*?)\*\//\n/gms; #/*(.*?)*/
1037 # Collapse whitespace into a single space or newline
1041 # Tokenize on non-identifier characters
1042 my @tokens0 = split(/(\W)/,$in);
1047 foreach $t (@tokens0) {
1049 next if (!$inString && ($t eq " " or $t eq ""));
1050 if ($inComment == 0)
1055 elsif ($inComment == 1)
1062 elsif ($inComment == 2)
1067 elsif ($inComment == 3)
1072 # if we were in a string, need to push previous '*'
1077 $inString = 0; # end of comment aborts a string
1096 # if ($VerboseMode) {print "string : [$t]\n"; }
1108 my $CurrentTraceFormatString;
1109 my $CurrentTraceFormatCategory;
1110 # format Key as specified by the @TraceFormatCategory tag is either the current category
1111 # or the current UID
1112 my $CurrentFormatTableKey;
1116 parse_scope($filescope, \@tokens, \$line);
1119 #print join (" ", @tokens);
1124 sub parse_scope($$$) {
1125 my ($scope, $tokens, $line) = @_;
1130 my $overall_align=0;
1131 # print ">parse_scope $scope->{name}\n";
1133 while (scalar(@$tokens))
1135 my $t = shift @$tokens;
1136 # printf "t: [$t] [$$line]\n";
1137 if (!defined ($t)) {
1138 printf "undefined !";
1141 if ($state>=-1 and $t eq "\n") {
1145 } elsif ($state==-1 and $t ne "\n") {
1147 } elsif ($state==-2 and $t ne ';') {
1151 if ($state>0 and $t eq '#') {
1152 $t = shift @$tokens;
1153 if ($t eq 'define') {
1154 my $ident = shift @$tokens;
1155 my $defn = shift @$tokens;
1156 if ($defn ne '(') { # don't do macros with parameters
1157 # print "MACRO: $ident :== $defn\n";
1158 $macros{$ident} = $defn;
1161 $state=-1; # skip to next line
1166 if (parse_doxygen($scope,$tokens, $line, $t) == 1)
1169 if ($t eq "namespace" ) {
1174 $cl{values}=$scope->{values};
1175 $cl{members}=\$scope->{members};
1176 $cl{typedefs}=\$scope->{typedefs};
1177 $cl{FormatTables}=$scope->{FormatTables};
1178 $cl{formatStrings} =$scope->{formatStrings};
1179 $cl{formatCategories} =$scope->{formatCategories};
1181 my $new_namespace = \%cl;
1182 my $n = get_token($scope,$tokens,$line);
1184 warn "Unnamed $t not supported at line $$line\n";
1187 $new_namespace->{name}=$n;
1188 my @class_match = grep {$_->{name} eq $n} @classes;
1189 my $exists = scalar(@class_match);
1190 my $b = get_token($scope,$tokens,$line);
1192 die "Inheritance not supported at line $$line\n";
1193 } elsif ($b eq ';') {
1194 # forward declaration
1195 push @classes, $new_namespace unless ($exists);
1197 } elsif ($b ne '{') {
1198 warn "Syntax error#1 at line $$line\n";
1202 $new_namespace = $class_match[0];
1203 if ($new_namespace->{complete}) {
1204 warn "Duplicate definition of $cl{specifier} $n\n";
1207 push @classes, $new_namespace unless ($exists);
1208 parse_scope($new_namespace, $tokens, $line);
1212 if ($t eq "struct" or $t eq "class" or $t eq "NONSHARABLE_CLASS") {
1213 next if ($state==0);
1220 $cl{members}=\@members;
1221 $cl{typedefs}=\@typedefs;
1222 $cl{FormatTables}=$scope->{FormatTables};
1223 my $new_class = \%cl;
1226 if ($t eq "NONSHARABLE_CLASS")
1228 my $b = get_token($scope,$tokens,$line);
1229 if ($b !~ /\(/) {die "Syntax error at line $$line\n";}
1230 $n = get_token($scope,$tokens,$line);
1231 $b = get_token($scope,$tokens,$line);
1232 if ($b !~ /\)/) {die "Syntax error at line $$line\n";}
1236 $n = get_token($scope,$tokens,$line);
1241 warn "Unnamed $t not supported at line $$line\n";
1244 $new_class->{name}=$n;
1245 my @class_match = grep {$_->{name} eq $n} @classes;
1246 my $exists = scalar(@class_match);
1247 my $b = get_token($scope,$tokens,$line);
1248 #skip inheritance etc until we get to a '{' or \ ';'
1249 while ($b ne '{' && $b ne ';')
1251 $b = get_token($scope,$tokens,$line);
1252 die "Syntax error#2 at line $$line\n" if (!defined $b);
1255 # forward declaration
1256 push @classes, $new_class unless ($exists);
1260 $new_class = $class_match[0];
1261 if ($new_class->{complete}) {
1262 warn "Duplicate definition of $cl{specifier} $n\n";
1265 push @classes, $new_class unless ($exists);
1266 parse_scope($new_class, $tokens, $line);
1268 } elsif ($t eq "enum") {
1270 my $n = get_token($scope,$tokens,$line);
1274 $n = get_token($scope,$tokens,$line);
1278 die "Syntax error#4 at line $$line\n";
1280 parse_enum($scope, $tokens, $line, $name);
1282 } elsif ($t eq '}') {
1284 if ($scope->{scope}) {
1285 if ($scope->{specifier} eq "namespace")
1287 $scope->{complete}=1;
1288 # print "Scope completed\n";
1291 $t = get_token($scope,$tokens,$line);
1293 while (defined ($t) and $t ne ';')
1294 {$t = get_token($scope,$tokens,$line);}
1295 die "Syntax error#5 at line $$line\n" if ($t ne ';');
1296 $scope->{complete}=1;
1297 # print "Scope completed\n";
1300 warn "Syntax error#5 at line $$line\n";
1304 if ($scope->{scope}) {
1305 if ($t eq "public" or $t eq "private" or $t eq "protected") {
1306 if (shift (@$tokens) eq ':') {
1307 next; # ignore access specifiers
1309 die "Syntax error#6 at line $$line\n";
1312 unshift @$tokens, $t;
1314 my @currdecl = parse_decl_def($scope, $tokens, $line);
1315 # print scalar (@currdecl), "\n";
1316 if ($t eq 'static') {
1317 next; # skip static members
1320 if ($t eq 'typedef') {
1321 # print "TYPEDEF\n";
1323 $t = shift @currdecl;
1326 # print "NOT TYPEDEF\n";
1329 # print "$currdecl[0]\n";
1330 next if (scalar(@currdecl)==0);
1332 if ($t eq "const") {
1333 # check for constant declaration
1334 # print "CONST $currdecl[1] $currdecl[2] $currdecl[3]\n";
1335 my $ctype = lookup_type($scope, $currdecl[1]);
1336 # print "$ctype->{basic} $ctype->{size}\n";
1337 if ($ctype->{basic} and $currdecl[2]=~/^\w+$/ and $currdecl[3] eq '=') {
1339 die "Syntax error#7 at line $$line\n";
1343 my $type = $ctype->{name};
1344 my $name; #### = shift @currdecl;
1348 $name = $scope->{name} . "::" . shift @currdecl;
1352 $name = shift @currdecl;
1354 # printf "[$name,$scope->{name}]";
1355 my $size = $ctype->{size};
1357 my $value = get_constant_expr($scope,\@currdecl,$line);
1358 $values{$name} = {type=>$type, size=>$size, value=>$value};
1368 sub get_token($$$) {
1369 my ($scope,$tokenlist,$line) = @_;
1370 while (scalar(@$tokenlist)) {
1371 my $t = shift @$tokenlist;
1372 return $t if (!defined($t));
1373 if (parse_doxygen($scope,$tokenlist, $line, $t) == 1)
1375 if ($t !~ /^[\s]*$/)
1377 if ($$tokenlist[0] eq ":" and $$tokenlist[1] eq ":")
1379 $t.= shift @$tokenlist;
1380 $t.= shift @$tokenlist;
1381 $t.= shift @$tokenlist;
1382 # print "Colon-separated token";
1391 sub skip_qualifiers($) {
1411 my $t = $$tokens[0];
1413 last unless (defined ($q));
1420 sub parse_indirection($) {
1424 my $t = $$tokens[0];
1430 last if ($t ne "const" and $t ne "volatile");
1436 sub get_operand($$$) {
1437 my ($scope,$tokens,$line) = @_;
1438 my $t = get_token($scope,$tokens,$line);
1440 my $x = get_operand($scope,$tokens,$line);
1442 } elsif ($t eq '+') {
1443 my $x = get_operand($scope,$tokens,$line);
1445 } elsif ($t eq '~') {
1446 my $x = get_operand($scope,$tokens,$line);
1448 } elsif ($t eq '!') {
1449 my $x = get_operand($scope,$tokens,$line);
1451 } elsif ($t eq '(') {
1452 my $x = get_constant_expr($scope,$tokens,$line);
1453 my $t = get_token($scope,$tokens,$line);
1455 warn "Missing ) at line $$line\n";
1459 } elsif ($t eq "sizeof") {
1460 my $ident = get_token($scope,$tokens,$line);
1461 if ($ident eq '(') {
1462 $ident = get_token($scope,$tokens,$line);
1463 my $cb = get_token($scope,$tokens,$line);
1465 warn "Bad sizeof() syntax at line $$line\n";
1469 $ident = look_through_macros($ident);
1470 if ($ident !~ /^\w+$/) {
1471 warn "Bad sizeof() syntax at line $$line\n";
1474 my $type = lookup_type($scope, $ident);
1475 if (!defined $type) {
1476 warn "Unrecognised type $ident at line $$line\n";
1479 if ($type->{basic}) {
1480 return $type->{size};
1481 } elsif ($type->{enum}) {
1483 } elsif ($type->{ptr}) {
1485 } elsif ($type->{fptr}) {
1488 my $al = $type->{class}->{align};
1489 my $sz = $type->{class}->{size};
1490 return ($sz+$al-1)&~($al-1);
1492 $t = look_through_macros($t);
1495 } elsif ($t =~ /^\d/) {
1497 } elsif ($t =~ /^\w+$/) {
1498 my $x = lookup_value($scope,$t);
1499 # die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
1501 print "Unrecognised identifier '$t' at line $$line\n" ;
1504 } elsif ($t =~ /^\w+::\w+$/) {
1505 my $x = lookup_value($scope,$t);
1506 # die "Unrecognised identifier '$t' at line $$line\n" unless defined($x);
1508 print "Unrecognised identifier '$t' at line $$line\n" ;
1512 warn "Syntax error#10 at line $$line\n";
1517 sub look_through_macros($) {
1519 while ($ident and $macros{$ident}) {
1520 $ident = $macros{$ident};
1525 sub lookup_value($$) {
1526 my ($scope,$ident) = @_;
1528 my $vl = $scope->{values};
1529 if (defined($vl->{$ident})) {
1530 return $vl->{$ident}->{value};
1532 $scope = $scope->{scope};
1537 sub lookup_type($$) {
1538 my ($scope,$ident) = @_;
1539 if ($basictypes{$ident}) {
1540 return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
1543 if ($basictypes{$ident}) {
1544 return {scope=>$scope, basic=>1, name=>$ident, size=>$basictypes{$ident} };
1546 my $el = $scope->{enums};
1547 my $cl = $scope->{classes};
1548 my $td = $scope->{typedefs};
1549 if (grep {$_ eq $ident} @$el) {
1550 return {scope=>$scope, enum=>1, name=>$ident, size=>4 };
1552 my @match_class = (grep {$_->{name} eq $ident} @$cl);
1553 if (scalar(@match_class)) {
1554 return {scope=>$scope, class=>$match_class[0]};
1556 my @match_td = (grep {$_->{name} eq $ident} @$td);
1557 if (scalar(@match_td)) {
1558 my $tdr = $match_td[0];
1559 my $cat = $tdr->{category};
1560 if ($cat eq 'basic' or $cat eq 'enum' or $cat eq 'class') {
1561 $ident = $tdr->{alias};
1564 return { scope=>$scope, $cat=>1, $size=>$tdr->{size} };
1567 $scope = $scope->{scope};
1572 sub get_mult_expr($$$) {
1573 my ($scope,$tokens,$line) = @_;
1574 my $x = get_operand($scope,$tokens,$line);
1577 $t = get_token($scope,$tokens,$line);
1579 my $y = get_operand($scope,$tokens,$line);
1581 } elsif ($t eq '/') {
1582 my $y = get_operand($scope,$tokens,$line);
1584 {$x = int($x / $y);}
1585 } elsif ($t eq '%') {
1586 my $y = get_operand($scope,$tokens,$line);
1588 {$x = int($x % $y);}
1593 unshift @$tokens, $t;
1597 sub get_add_expr($$$) {
1598 my ($scope,$tokens,$line) = @_;
1599 my $x = get_mult_expr($scope,$tokens,$line);
1602 $t = get_token($scope,$tokens,$line);
1604 my $y = get_mult_expr($scope,$tokens,$line);
1606 } elsif ($t eq '-') {
1607 my $y = get_mult_expr($scope,$tokens,$line);
1613 unshift @$tokens, $t;
1617 sub get_shift_expr($$$) {
1618 my ($scope,$tokens,$line) = @_;
1619 my $x = get_add_expr($scope,$tokens,$line);
1622 $t = get_token($scope,$tokens,$line);
1623 if ($t eq '<' or $t eq '>') {
1624 $t2 = get_token($scope,$tokens,$line);
1626 unshift @$tokens, $t2;
1631 my $y = get_add_expr($scope,$tokens,$line);
1633 } elsif ($t eq '>') {
1634 my $y = get_add_expr($scope,$tokens,$line);
1640 unshift @$tokens, $t;
1644 sub get_and_expr($$$) {
1645 my ($scope,$tokens,$line) = @_;
1646 my $x = get_shift_expr($scope,$tokens,$line);
1649 $t = get_token($scope,$tokens,$line);
1651 my $y = get_shift_expr($scope,$tokens,$line);
1657 unshift @$tokens, $t;
1661 sub get_xor_expr($$$) {
1662 my ($scope,$tokens,$line) = @_;
1663 my $x = get_and_expr($scope,$tokens,$line);
1666 $t = get_token($scope,$tokens,$line);
1668 my $y = get_and_expr($scope,$tokens,$line);
1674 unshift @$tokens, $t;
1678 sub get_ior_expr($$$) {
1679 my ($scope,$tokens,$line) = @_;
1680 my $x = get_xor_expr($scope,$tokens,$line);
1683 $t = get_token($scope,$tokens,$line);
1685 my $y = get_xor_expr($scope,$tokens,$line);
1691 unshift @$tokens, $t;
1695 sub get_constant_expr($$$) {
1696 my ($scope,$tokens,$line) = @_;
1697 my $x = get_ior_expr($scope,$tokens,$line);
1701 sub parse_enum($$$$) {
1702 my ($scope,$tokens,$line,$enum_name) = @_;
1703 my $vl = $scope->{values};
1704 my $fstr = $scope->{formatStrings};
1705 my $fcat = $scope->{formatCategories};
1706 my $fmtTable = $scope->{FormatTables};
1710 my $t = get_token($scope,$tokens,$line);
1711 last if ($t eq '}');
1713 die "Unexpected end of file #2 at line $$line\n";
1720 if ($t !~ /^\w+$/) {
1721 warn "Syntax error#11 at line $$line\n";
1727 $t = $scope->{name} . "::" . $t;
1730 if (defined($vl->{$t})) {
1731 warn "Duplicate identifier [$t] at line $$line\n";
1733 my $t2 = get_token($scope,$tokens,$line);
1735 $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
1736 $fstr->{$t} = $CurrentTraceFormatString;
1737 $fcat->{$t} = $CurrentTraceFormatCategory;
1738 if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
1739 { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
1740 undef $CurrentTraceFormatString;
1742 } elsif ($t2 eq '}') {
1743 $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
1744 $fstr->{$t} = $CurrentTraceFormatString;
1745 $fcat->{$t} = $CurrentTraceFormatCategory;
1746 if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
1747 { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
1748 undef $CurrentTraceFormatString;
1751 } elsif ($t2 eq '=') {
1752 $x = get_constant_expr($scope, $tokens, $line);
1753 $vl->{$t} = {type=>$enum_name, size=>4, value=>$x, enum=>1};
1754 $fstr->{$t} = $CurrentTraceFormatString;
1755 $fcat->{$t} = $CurrentTraceFormatCategory;
1756 if (defined $CurrentTraceFormatCategory && defined $CurrentTraceFormatString)
1757 { $fmtTable->{$CurrentTraceFormatCategory}{$x} = $CurrentTraceFormatString; }
1758 undef $CurrentTraceFormatString;
1760 $t2 = get_token($scope,$tokens,$line);
1761 last if ($t2 eq '}');
1762 next if ($t2 eq ',');
1763 warn "Syntax error#12 at line $$line\n";
1765 unshift @$tokens, $t2;
1768 my $t = get_token($scope,$tokens,$line);
1770 warn "Missing ; at line $$line\n";
1775 sub parse_decl_def($$$) {
1776 my ($scope,$tokens,$line) = @_;
1779 while ( scalar(@$tokens) ) {
1780 my $t = get_token($scope,$tokens, $line);
1781 if ( (!defined ($t) || $t eq ';') and ($level==0)) {
1796 warn "Syntax error#13 at line $$line\n";
1797 unshift @$tokens, $t;
1802 return (); # end of function definition reached
1806 die "Unexpected end of file #3 at line $$line\n";
1811 my $el = $scope->{enums};
1812 my $cl = $scope->{classes};
1813 my $vl = $scope->{values};
1814 my $fstr = $scope->{formatStrings};
1815 my $fcat = $scope->{formatCategories};
1816 print "SCOPE: $scope->{name}\n";
1823 if (scalar(keys(%$vl))) {
1824 print "\tvalues:\n";
1825 foreach $vname (keys(%$vl)) {
1826 my $v = $vl->{$vname};
1827 my $x = $v->{value};
1829 my $sz = $v->{size};
1830 my $fstring = $fstr->{$vname};
1831 my $fcategory = $fcat->{$vname};
1833 printf ("\t\t$vname\=$x (enum $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory,$fstring);
1835 printf ("\t\t$vname\=$x (type $t) size=$sz fcat=[0x%x] fstr=[%s]\n", $fcategory, $fstring);
1839 if ($scope->{scope}) {
1840 my $members = $scope->{members};
1841 foreach (@$members) {
1843 my $sz = $_->{size};
1844 my $off = $_->{offset};
1845 my $spc = $_->{spacing};
1847 print "\t$n\[\]\: spacing $spc size $sz offset $off\n";
1849 print "\t$n\: size $sz offset $off\n";
1852 print "\tOverall size : $scope->{size}\n";
1853 print "\tOverall align: $scope->{align}\n";
1863 sub parse_doxygen($$$$) {
1864 my ($scope,$tokens,$line,$t) = @_;
1868 return 0; # not a doxygen comment
1872 my $t2 = shift @$tokens;
1873 my $t3 = shift @$tokens;
1875 if ($t2 ne "*" || $t3 ne "*")
1877 unshift @$tokens, $t3;
1878 unshift @$tokens, $t2;
1879 return 0; # not a doxygen comment
1882 # printf "doxygen start on line %d\n", $$line;
1884 my $t = shift @$tokens;
1887 warn "Unexpected end of file #4 at line $$line\n";
1891 if ($t eq "\n"){++$$line };
1895 my $t2 = shift @$tokens;
1896 last if ($t2 eq '/');
1897 unshift @$tokens, $t2;
1902 my $t2 = shift @$tokens;
1903 if ($t2 eq 'SYMTraceFormatString')
1905 my $t3 = shift @$tokens;
1906 # if ($VerboseMode){print "SYMTraceFormatString = [$t3]\n";}
1907 $CurrentTraceFormatString = $t3;
1909 if ($t2 eq 'SYMTraceFormatCategory')
1911 $CurrentTraceFormatCategory = get_operand($scope,$tokens,$line);
1912 # if ($VerboseMode){printf ("SYMTraceFormatCategory = 0x%x\n", $CurrentTraceFormatCategory);}
1916 unshift @$tokens, $t2;
1921 # printf ("doxygen end on line %d\n", $$line);
1922 return 1; # is a doxygen comment