#Copyright (c) 1992-2000 Microsoft Corporation # #Module Name: # # gnbugcds.pl # #Abstract: # # WinDbg Extension Api # #Environment: # # User Mode. # #Revision History: # # Kshitix K. Sharma (kksharma) # # # Parse bugcodes.txt file to generate C-relevant info for bugcheck codes # # Expected format of a bugcheck description: # # BUGCHECK # () # optional - # optional - PARAMETERS # Param [1|2|3|4] - # OR # Param [1|2|3|4] # VALUES: # [ : ]* # END_VALUES #DESCRIPTION # # sub emit_file_header; sub emit_bugcheck_info; sub emit_param_info; sub next_line; sub is_new_bugcheck; sub is_bugcheck_description; # # main # $NumLine = 0; @BugCheckList = {}; @FullParamDesc = {"", "", "", ""}; $ParamValueRec = { VALUE => 0, PARAMID => -1, PARAM1DESC => "", PARAM2DESC => "", PARAM3DESC => "", PARAM4DESC => "", }; @ParamValueRecList = {}; while ($arg = shift) { if ($arg eq "-o") { $OutFileName = shift; } elsif ($arg eq "-i") { $BugCheckTxtFile = shift; } else { $BugCheckTxtFile = $arg; } } die "Cannot open file $BugCheckTxtFile\n" if !open(BUGC_FILE, $BugCheckTxtFile); emit_file_header(); while (is_new_bugcheck() || next_line ) { $line = $_ if !is_new_bugcheck(); if (is_new_bugcheck()) { emit_bugcheck_info; } } continue { close BUGC_FILE if eof; } # emit a list of APIS for quick reference print OUT_FILE "BUGDESC_APIREFS g_BugDescApiRefs[] = {\n"; for $i(1..$#BugCheckList) { printf (OUT_FILE " { %30s, &BugCheck%s},\n", $BugCheckList[ $i ], $BugCheckList[ $i ]); } print OUT_FILE "};\n"; print OUT_FILE "ULONG g_NumBugDescApiRefs = sizeof(g_BugDescApiRefs) / sizeof(BUGDESC_APIREFS);\n"; # # Subroutines # sub is_new_bugcheck { if ($line =~ /^BUGCHECK$/) { next_line; } if ($line =~ /^([A-Z][A-Z_0-9]+)\s*\((.*)\)$/) { return 1; } return 0; } sub is_bugcheck_description { if ($line =~ /^DESCRIPTION\s*$/) { return 1; } return 0; } sub emit_file_header { die "Cannot open file $OutFileName\n" if !open(OUT_FILE, ">" . $OutFileName); print OUT_FILE "//-------------------------------------". "--------------------------------------\n"; print OUT_FILE "//\n"; print OUT_FILE "// IMPORTANT: This file is automatically generated.\n"; print OUT_FILE "// Do not edit by hand.\n"; print OUT_FILE "//\n"; print OUT_FILE "// Generated from $BugCheckTxtFile " . localtime() . "\n"; print OUT_FILE "//\n"; print OUT_FILE "//-------------------------------------". "--------------------------------------\n\n"; print OUT_FILE "#include \"precomp.h\"\n"; print OUT_FILE "\n\n"; } sub emit_bugcheck_header { print OUT_FILE "//\n"; print OUT_FILE "// DescriptionRoutine for $_[0] ($_[1])\n"; print OUT_FILE "//\n"; print OUT_FILE "void\nBugCheck$_[0] ( \n"; print OUT_FILE " PBUGCHECK_ANALYSIS pBugCheck\n"; print OUT_FILE " )\n"; print OUT_FILE "{\n"; print OUT_FILE " ULONG Value = $_[0];\n"; print OUT_FILE " PCHAR BugName = \"$_[0]\";\n"; print OUT_FILE " PCHAR Description = NULL, ParamDesc[4] = {0};\n\n"; } sub init_param_array { for $i (0..3) { if ($FullParamDesc[ $i ] =~ /.+/) { # Non NULL values only print OUT_FILE "$_[0]$FullParamDesc[ $i ];\n"; } } } sub begin_first_value { # $_[0] -> Argument index # $_[1] -> Argument value print OUT_FILE "$_[2]if (pBugCheck->Args[ $_[0] ] == $_[1]) {\n"; } sub begin_intermediate_value { # $_[0] -> Argument index # $_[1] -> Argument value # $_[2] -> Indent init_param_array($_[2]); print OUT_FILE "$_[2]} else if (pBugCheck->Args[ $_[0] ] == $_[1]) {\n"; } sub begin_intermediate_value_parent { # $_[0] -> Argument index # $_[1] -> Argument value # $_[2] -> Indent print OUT_FILE "$_[2]} else if (pBugCheck->Args[ $_[0] ] == $_[1]) {\n"; } sub end_value { # $_[0] -> Indent init_param_array($_[0]); print OUT_FILE "$_[0]}\n"; } sub emit_bugcheck_end { print OUT_FILE " pBugCheck->Code = Value;\n"; print OUT_FILE " pBugCheck->szName = BugName;\n"; print OUT_FILE " pBugCheck->szDescription = Description;\n"; print OUT_FILE " pBugCheck->szParamsDesc[0] = ParamDesc[0];\n"; print OUT_FILE " pBugCheck->szParamsDesc[1] = ParamDesc[1];\n"; print OUT_FILE " pBugCheck->szParamsDesc[2] = ParamDesc[2];\n"; print OUT_FILE " pBugCheck->szParamsDesc[3] = ParamDesc[3];\n"; print OUT_FILE "\n}\n\n"; } # # Match the folowing here # () # # - done by emit_param_info # # sub emit_bugcheck_info { die "No name Info on line $NumLine\n" if !($BugNameLine = $line) ; if (($Name,$Value) = $BugNameLine =~ /^([A-Z][A-Z_0-9]+)\s*\((.*)\)$/) { emit_bugcheck_header ( $Name, $Value ); push (@BugCheckList, $Name); $FullDesc = " Description = "; $DescPrinted = 0; while (next_line && (!is_new_bugcheck()) && ($line !~ /^\s*PARAMETERS\s*.*$/)) { if ($line !~ /^\s*$/) { ($Desc) = $line =~ /^(.*)\s*$/; if ($DescPrinted) { $FullDesc = $FullDesc . "\n\t"; } ($Desc) =~ s/([\\"])/\\$1/g ; $FullDesc = $FullDesc . "\"$Desc\\n\""; $DescPrinted++; } } $MoreDesc = 0; if ($line =~ /^\s*PARAMETERS\s*.*$/) { ($line) = $line =~ /^\s*PARAMETERS\s*(.*)$/; if (!$line) { next_line; } $MoreDesc = emit_param_info; } if ($MoreDesc) { # BugCheck description string following parameter description while (next_line && (!is_new_bugcheck())) { if ($line !~ /^\s*$/) { ($Desc) = $line =~ /^(.*)\s*$/; if ($DescPrinted) { $FullDesc = $FullDesc . "\n\t"; } ($Desc) =~ s/([\\"])/\\$1/g ; $FullDesc = $FullDesc . "\"$Desc\\n\""; $DescPrinted++; } } } if (!$DescPrinted) { $FullDesc = $FullDesc . "\"\"";} print OUT_FILE $FullDesc . ";\n"; emit_bugcheck_end ; } else { print "Bad name Info on line $NumLine - $BugNameLine\n" } } sub emit_param_info { @FullParamDesc = {"", "", "", ""}; $ParamValueDefined = -1; $IsFirstValue = 1; @ParamValueRecList = {}; $Level = 0; $MovedLevelUp = 0; $FullParamDesc[ 0 ] = ""; $FullParamDesc[ 1 ] = ""; $FullParamDesc[ 2 ] = ""; $FullParamDesc[ 3 ] = ""; while (!is_new_bugcheck() && !is_bugcheck_description() && $line) { if ($line !~ /^\s*$/) { ($ParamPrefix, $ParamId, $ParamDesc) = $line =~ /^\s*(\w*)\s*([1234])\s*-\s*(.*)$/; if ($ParamId && ($ParamPrefix == "" || $ParamPrefix == "Param" || $ParamPrefix == "Arg" || $ParamPrefix == "Parameter" || $ParamPrefix == "Argument")) { ($ParamDesc) =~ s/([\\"])/\\$1/g ; $ParamId--; # 0 based index $FullParamDesc[ $ParamId ] = " ParamDesc[ $ParamId ] = \"$ParamDesc\""; $LastParamId = $ParamId; } elsif ($line =~ /^\s*VALUES\s*:?\s*$/) { # emit the parameter description we have so far since the folowing # ones would be relevant to specific values only. # code path will automatically remember these if they are not defined later init_param_array(" " x ($Level * 4)); $ParamValueDefined = $LastParamId; $IsFirstValue = 1; $ParamValueRec = { VALUE => 0, PARAMID => $LastParamId, PARAM1DESC => $FullParamDesc[ 0 ], PARAM2DESC => $FullParamDesc[ 1 ], PARAM3DESC => $FullParamDesc[ 2 ], PARAM4DESC => $FullParamDesc[ 3 ], }; push (@ParamValueRecList, ($ParamValueRec)); $Level = $#ParamValueRecList; } elsif ($line =~ /^\s*END_VALUES\s*$/) { $Level = $#ParamValueRecList; end_value(" " x ($Level * 4)); $IsFirstValue = 0; $MovedLevelUp = 1; # restore what we had whe we saw VALUES clause $LastParamId = $ParamValueRecList[$Level-1]{PARAMID}; $FullParamDesc[ 0 ] = $ParamValueRecList[$Level-1]{PARAM1DESC}; $FullParamDesc[ 1 ] = $ParamValueRecList[$Level-1]{PARAM2DESC}; $FullParamDesc[ 2 ] = $ParamValueRecList[$Level-1]{PARAM3DESC}; $FullParamDesc[ 3 ] = $ParamValueRecList[$Level-1]{PARAM4DESC}; if ($Level) { pop( @ParamValueRecList ); } else { die "No preivious VALUE clause for END_VALUES on line $NumLine\n"; } $ParamValueDefined = $LastParamId; $Level = $#ParamValueRecList; if ($Level == 0) { $ParamValueDefined = -1; } } elsif (($ParamValueDefined != -1) && (($Value) = $line =~ /^\s*(0?x?[0-9A-Fa-f]*)\s*:.*$/)) { #matched " : " if ($Value !~ /0x.*/) { # prepend 0x $Value = "0x" . $Value; } if ($IsFirstValue) { $IsFirstValue = 0; begin_first_value($ParamValueDefined, $Value, " " x ($Level * 4)); } elsif ($MovedLevelUp) { $MovedLevelUp = 0; begin_intermediate_value_parent($ParamValueDefined, $Value, " " x ($Level * 4)); } else { begin_intermediate_value($ParamValueDefined, $Value, " " x ($Level * 4)); } $ParamDesc = $FullParamDesc[ $ParamValueDefined ]; if (($Desc) = $line =~ /^\s*0?x?[0-9A-Fa-f]*\s*:\s*(.*)$/) { ($Desc) =~ s/([\\"])/\\$1/g ; $FullParamDesc[ $ParamValueDefined ] = " ParamDesc[ $ParamValueDefined ] = \"$Desc\""; } else { $FullParamDesc[ $ParamValueDefined ] = $ParamDesc; } } else { ($line) = $line =~ /^\s*(.*)$/; ($line) =~ s/([\\"])/\\$1/g ; #"/# escape chars $temp = "\\n\""; $FullParamDesc[ $LastParamId ] = $FullParamDesc[ $LastParamId ] . "\n \"\\n$line\""; } } $line = next_line; } if ($ParamValueDefined != -1) { end_value(" " x (4)); } else { init_param_array(""); } $MoreDesc = is_bugcheck_description(); return $MoreDesc; } sub next_line { $line = ; $NumLine++; while ($line =~ /\s*\%.*$/) { # Skip commented lines - ones which beging with % $line = ; $NumLine++; } return $line; }