windows-nt/Source/XPSP1/NT/base/tools/kdexts2/gnbugcds.pl
2020-09-26 16:20:57 +08:00

371 lines
11 KiB
Perl

#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
# <bugcheck name> (<numericvalue>)
# optional - <multiline description string about bugcheck>
# optional - PARAMETERS <parameters description as follows>
# Param [1|2|3|4] - <string>
# OR
# Param [1|2|3|4]
# VALUES:
# [<value> : <Rest of parameter description>]*
# END_VALUES <required only in case of nesting>
#DESCRIPTION
#<additional description string>
#
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
# <BugName> (<num>)
# <description>
# <parameters> - done by emit_param_info
# <more description>
#
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 "<Value> : <text>"
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 = <BUGC_FILE>;
$NumLine++;
while ($line =~ /\s*\%.*$/) {
# Skip commented lines - ones which beging with %
$line = <BUGC_FILE>;
$NumLine++;
}
return $line;
}