windows-nt/Source/XPSP1/NT/sdktools/gensrv/gensrv.c
2020-09-26 16:20:57 +08:00

881 lines
24 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
gensrv.c
Abstract:
This module implements a program which generates the system service
dispatch table that is used by the trap handler and the system service
stub procedures which are used to call the services. These files are
both generated as text files that must be run through the assembler
to produce the actual files.
This program can also be used to generate the user mode system service
stub procedures.
If the -P switch is provided, it will also generate Profile
in the user mode system service stub procedures.
Author:
David N. Cutler (davec) 29-Apr-1989
Environment:
User mode.
Revision History:
Russ Blake (russbl) 23-Apr-1991 - add Profile switch
--*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
CHAR InputFileNameBuffer[ 128 ];
CHAR StubFileNameBuffer[ 128 ];
CHAR TableFileNameBuffer[ 128 ];
CHAR StubHeaderNameBuffer[ 128 ];
CHAR TableHeaderNameBuffer[ 128 ];
CHAR ProfFileNameBuffer[ 128 ];
CHAR ProfHeaderNameBuffer[ 128 ];
CHAR ProfDotHFileNameBuffer[ 128 ];
CHAR ProfIncFileNameBuffer[ 128 ];
CHAR ProfTblFileNameBuffer[ 128 ];
CHAR InputRecord[132];
CHAR OutputRecord[132];
#define GENSRV_MAXSERVICES 1000
CHAR MemoryArgs[GENSRV_MAXSERVICES];
CHAR ErrorReturns[GENSRV_MAXSERVICES];
// Increment this everytime a change to this file is made
#define GENSRV_VERSION "1.3"
#define GENSRV_MACRONAME "STUBS_ENTRY%d"
#define GENSRV_MACROARGS " %d, %s, %d"
PCHAR UsrStbsFmtMacroName = "USR" GENSRV_MACRONAME;
#define USRSTUBS_MAXARGS 8
PCHAR SysStbsFmtMacroName = "SYS" GENSRV_MACRONAME;
PCHAR StbFmtMacroArgs = GENSRV_MACROARGS;
PCHAR TableEntryFmtNB = "TABLE_ENTRY %s, %d, %d \n";
PCHAR TableEntryFmtB = "TABLE_ENTRY( %s, %d, %d )\n";
PCHAR TableEntryFmt;
PCHAR ProfTblFmt = "\t\t\"%s\",\n";
PCHAR ProfDotHFmt = "#define NAP_API_COUNT %d \n";
PCHAR ProfIncFmt = "NapCounterServiceNumber\tEQU\t%d\n";
PCHAR ProfTblPrefixFmt = "#include <nt.h>\n\n"
"PCHAR NapNames[] = {\n\t\t\"NapCalibrationData\",\n";
PCHAR ProfTblSuffixFmt = "\t\t\"NapTerminalEntry\" };\n";
VOID
ClearArchiveBit(
PCHAR FileName
);
SHORT ParseAndSkipShort(
CHAR **ppBuffer
);
VOID
PrintStubLine (
FILE * pf,
SHORT Index1,
PCHAR pszMacro,
SHORT ServiceNumber,
SHORT ArgIndex,
SHORT *Arguments,
SHORT Braces);
VOID
GenerateTable(
FILE * pf,
PCHAR pszMacro,
SHORT ServiceNumber,
SHORT Args,
SHORT Braces
);
int __cdecl
main (argc, argv)
int argc;
char *argv[];
{
LONG InRegisterArgCount;
SHORT Index1;
SHORT Index2;
SHORT Limit;
FILE *InputFile;
CHAR *Ipr;
CHAR *Opr;
SHORT ServiceNumber = 0;
SHORT TotalArgs = 0;
SHORT NapCounterServiceNumber;
FILE *StubFile;
FILE *TableFile;
FILE *DebugFile;
FILE *StubHeaderFile;
FILE *TableHeaderFile;
FILE *DefFile;
FILE *ProfFile;
FILE *ProfHeaderFile;
FILE *ProfDotHFile;
FILE *ProfIncFile;
FILE *ProfTblFile;
CHAR Terminal;
CHAR *GenDirectory;
CHAR *AltOutputDirectory;
CHAR *StubDirectory;
CHAR *InputFileName;
CHAR *StubFileName = NULL;
CHAR *TableFileName;
CHAR *StubHeaderName = NULL;
CHAR *TableHeaderName = NULL;
CHAR *TargetDirectory;
CHAR *TargetExtension;
CHAR *DefFileData;
CHAR *ProfFileName;
CHAR *ProfHeaderName;
CHAR *ProfDotHFileName;
CHAR *ProfIncFileName;
CHAR *ProfTblFileName;
SHORT Braces;
SHORT DispatchCount;
SHORT Profile;
SHORT LineStart;
SHORT LineEnd;
SHORT Arguments[ USRSTUBS_MAXARGS ];
SHORT ArgIndex;
SHORT ErrorReturnTable;
if (argc == 2 && (!strcmp(argv[1],"-?") || !strcmp(argv[1],"/?"))) {
PrintUsage:
printf("GENSRV: System Service Dispatch Table Generator. Version " GENSRV_VERSION "\n");
printf("Usage: gensrv [-d targetdir] [-e targetext] [-f defdata] [-B] [-P] [-C] [-R] [-a altoutputdir] [-s stubdir] [services.tab directory]\n");
printf("-B Use braces\n");
printf("-P Generate profile stubs data\n");
printf("-C Spew dispatch count\n");
printf("-R Generate ConvertToGui error return table\n");
exit(1);
}
//
// Determine name of target directory for output files. Requires that
// the -d switch be specified and that the argument after the switch is
// the target directory name. If no -d switch then defaults to "."
//
if (argc >= 3 && !strcmp(argv[1],"-d")) {
TargetDirectory = argv[2];
argc -= 2;
argv += 2;
} else {
TargetDirectory = ".";
}
//
// Determine name of target extension for output files. Requires that
// the -e switch be specified and that the argument after the switch is
// the target extension string. If no -e switch then defaults to "s"
//
if (argc >= 3 && !strcmp(argv[1],"-e")) {
TargetExtension = argv[2];
argc -= 2;
argv += 2;
} else {
TargetExtension = "s";
}
//
// Determine if def file data is to be generated
//
if (argc >= 3 && !strcmp(argv[1],"-f")) {
DefFileData = argv[2];
argc -= 2;
argv += 2;
} else {
DefFileData = NULL;
}
//
// Change default directory used for generated files.
//
if (argc >= 3 && !strcmp(argv[1],"-g")) {
GenDirectory = argv[2];
argc -= 2;
argv += 2;
} else {
GenDirectory = ".";
}
//
// Change name of usrstubs.s
//
if (argc >= 3 && !strcmp(argv[1],"-stubs")) {
StubFileName = argv[2];
argc -= 2;
argv += 2;
}
//
// Change name of services.stb
//
if (argc >= 3 && !strcmp(argv[1],"-sstb")) {
StubHeaderName = argv[2];
argc -= 2;
argv += 2;
}
if (argc >= 3 && !strcmp(argv[1],"-stable")) {
TableHeaderName = argv[2];
argc -= 2;
argv += 2;
}
//
// Determine if braces are to be generated
//
if (argc >= 2 && !strcmp(argv[1],"-B")) {
Braces = 1;
argc -= 1;
argv += 1;
} else {
Braces = 0;
}
//
// Determine if services Profile stubs data is to be generated
//
if (argc >= 2 && !strcmp(argv[1],"-P")) {
Profile = 1;
argc -= 1;
argv += 1;
} else {
Profile = 0;
}
//
// Determine if dispatch count should be spewed
//
if (argc >= 2 && !strcmp(argv[1],"-C")) {
DispatchCount = 1;
argc -= 1;
argv += 1;
} else {
DispatchCount = 0;
}
//
// Determine if error return table should be generated
//
if (argc >= 2 && !strcmp(argv[1],"-R")) {
ErrorReturnTable = 1;
argc -= 1;
argv += 1;
} else {
ErrorReturnTable = 0;
}
//
// ALT_PROJECT output directory.
//
if (argc >= 3 && !strcmp(argv[1],"-a")) {
AltOutputDirectory = argv[2];
argc -= 2;
argv += 2;
} else {
AltOutputDirectory = GenDirectory;
}
//
// table.stb and services.stb directory.
//
if (argc >= 3 && !strcmp(argv[1],"-s")) {
StubDirectory = argv[2];
argc -= 2;
argv += 2;
} else {
StubDirectory = GenDirectory;
}
//
// Determine name of input and output files, based on the argument
// to the program. If no argument other than program name, then
// generate the kernel mode system service files (stubs and dispatch
// table). Otherwise, expect a single argument that is the path name
// of the services.tab file and produce output file(s), which
// contain the user mode system service stubs (and profiled stubs if
// selected.)
//
if (argc == 1) {
if (DefFileData) {
goto PrintUsage;
}
sprintf(InputFileName = InputFileNameBuffer,
"%s\\services.tab",GenDirectory);
sprintf(StubFileName = StubFileNameBuffer,
"%s\\sysstubs.%s",AltOutputDirectory,TargetExtension);
sprintf(TableFileName = TableFileNameBuffer,
"%s\\systable.%s",AltOutputDirectory,TargetExtension);
if (TableHeaderName == NULL) {
sprintf(TableHeaderName = TableHeaderNameBuffer,
"%s\\table.stb",StubDirectory);
}
if (StubHeaderName == NULL) {
sprintf(StubHeaderName = StubHeaderNameBuffer,
"%s\\services.stb",StubDirectory);
}
} else {
if (argc == 2) {
if (StubDirectory == GenDirectory) {
StubDirectory = argv[1];
}
sprintf(InputFileName = InputFileNameBuffer,
"%s\\services.tab",argv[1]);
if (DefFileData == NULL) {
if (StubFileName == NULL) {
sprintf(StubFileName = StubFileNameBuffer,
"%s\\usrstubs.%s",TargetDirectory,TargetExtension);
}
if (StubHeaderName == NULL) {
sprintf(StubHeaderName = StubHeaderNameBuffer,
"%s\\services.stb",StubDirectory);
}
if (Profile) {
sprintf(ProfFileName = ProfFileNameBuffer,
"%s\\napstubs.%s",TargetDirectory,TargetExtension);
sprintf(ProfHeaderName = ProfHeaderNameBuffer,
"%s\\%s\\services.nap",argv[1],TargetDirectory);
sprintf(ProfDotHFileName = ProfDotHFileNameBuffer,
".\\ntnapdef.h");
sprintf(ProfIncFileName = ProfIncFileNameBuffer,
"%s\\ntnap.inc",TargetDirectory);
sprintf(ProfTblFileName = ProfTblFileNameBuffer,
".\\ntnaptbl.c");
}
}
TableFileName = NULL;
} else {
goto PrintUsage;
}
}
//
// Open input and output files.
//
InputFile = fopen(InputFileName, "r");
if (!InputFile) {
printf("\nfatal error Unable to open system services file %s\n", InputFileName);
goto PrintUsage;
}
if (DefFileData == NULL) {
StubFile = fopen(StubFileName, "w");
if (!StubFile) {
printf("\nfatal error Unable to open system services file %s\n", StubFileName);
fclose(InputFile);
exit(1);
}
StubHeaderFile = fopen(StubHeaderName, "r");
if (!StubHeaderFile) {
printf("\nfatal error Unable to open system services stub file %s\n", StubHeaderName);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
if (Profile) {
ProfHeaderFile = fopen(ProfHeaderName, "r");
if (!ProfHeaderFile) {
printf("\nfatal error Unable to open system services profiling stub file %s\n", ProfHeaderName);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
ProfFile = fopen(ProfFileName, "w");
if (!ProfFile) {
printf("\nfatal error Unable to open system services file %s\n", ProfFileName);
fclose(ProfHeaderFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
ProfDotHFile = fopen(ProfDotHFileName, "w");
if (!ProfDotHFile) {
printf("\nfatal error Unable to open system services file %s\n", ProfFileName);
fclose(ProfFile);
fclose(ProfHeaderFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
ProfIncFile = fopen(ProfIncFileName, "w");
if (!ProfIncFile) {
printf("\nfatal error Unable to open system services file %s\n", ProfFileName);
fclose(ProfFile);
fclose(ProfHeaderFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
ProfTblFile = fopen(ProfTblFileName, "w");
if (!ProfTblFile) {
printf("\nfatal error Unable to open system services file %s\n", ProfFileName);
fclose(ProfIncFile);
fclose(ProfDotHFile);
fclose(ProfFile);
fclose(ProfHeaderFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
}
}
if (TableFileName != NULL) {
TableFile = fopen(TableFileName, "w");
if (!TableFile) {
printf("\nfatal error Unable to open system services file %s\n",
TableFileName);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
TableHeaderFile = fopen(TableHeaderName, "r");
if (!TableHeaderFile) {
printf("\nfatal error Unable to open system services stub file %s\n",
TableHeaderName);
fclose(TableFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
} else {
TableFile = NULL;
TableHeaderFile = NULL;
}
if ( DefFileData ) {
DefFile = fopen(DefFileData, "w");
if (!DefFile) {
printf("\nfatal error Unable to open def file data file %s\n", DefFileData);
if ( TableFile ) {
fclose(TableHeaderFile);
fclose(TableFile);
}
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
} else {
DefFile = NULL;
}
//
// Output header information to the stubs file and table file. This
// information is obtained from the Services stub file and from the
// table stub file.
//
if (DefFile == NULL) {
while( fgets(InputRecord, 132, StubHeaderFile) ) {
fputs(InputRecord, StubFile);
}
if (Profile) {
while( fgets(InputRecord, 132, ProfHeaderFile) ) {
fputs(InputRecord, ProfFile);
}
fputs(ProfTblPrefixFmt, ProfTblFile);
}
}
if (TableFile != NULL) {
if (!fgets(InputRecord, 132, TableHeaderFile) ) {
printf("\nfatal error Format Error in table stub file %s\n", TableHeaderName);
fclose(TableHeaderFile);
fclose(TableFile);
fclose(StubHeaderFile);
fclose(StubFile);
fclose(InputFile);
exit(1);
}
InRegisterArgCount = atol(InputRecord);
while( fgets(InputRecord, 132, TableHeaderFile) ) {
fputs(InputRecord, TableFile);
}
} else {
InRegisterArgCount = 0;
}
if (Braces) {
TableEntryFmt = TableEntryFmtB;
} else {
TableEntryFmt = TableEntryFmtNB;
}
//
// Read service name table and generate file data.
//
while ( fgets(InputRecord, 132, InputFile) ){
//
// Generate stub file entry.
//
Ipr = &InputRecord[0];
Opr = &OutputRecord[0];
//
// If services.tab was generated by C_PREPROCESSOR, there might
// be empty lines in this file. Using the preprocessor allows
// people to use #ifdef, #includes, etc in the original services.tab
//
switch (*Ipr) {
case '\n':
case ' ':
continue;
}
while ((*Ipr != '\n') && (*Ipr != ',')) {
*Opr++ = *Ipr++;
}
*Opr = '\0';
//
// If the input record ended in ',', then the service has inmemory
// arguments and the number of in memory arguments follows the comma.
//
MemoryArgs[ServiceNumber] = 0;
Terminal = *Ipr;
*Ipr++ = 0;
if (Terminal == ',') {
MemoryArgs[ServiceNumber] = (char) atoi(Ipr);
}
// Move to the end of the line or past the next comma
while (*Ipr != '\n') {
if (*Ipr++ == ',') {
break ;
}
}
//
// If an error return value table is to be generated, then the following value
// might follow:
// 0 = return 0
// -1 = return -1
// 1 = return status code. (This is the default if no value is specified)
//
// This table is used by the dispatcher when convertion to GUI fails.
//
if (ErrorReturnTable) {
if (*Ipr != '\n') {
ErrorReturns[ServiceNumber] = (char)ParseAndSkipShort(&Ipr);
} else {
ErrorReturns[ServiceNumber] = 1;
}
}
//
//
// If there are more arguments, then this stub doesn't use the default code (lines 1 to 8)
// The following format is expected:
// LineStart,LineEnd,Argument1[,Argument2[,Argument3]....]
//
ArgIndex = 0;
if (*Ipr != '\n') {
LineStart = ParseAndSkipShort(&Ipr);
LineEnd = ParseAndSkipShort(&Ipr);
while ((ArgIndex < USRSTUBS_MAXARGS) && (*Ipr != '\n')) {
Arguments[ ArgIndex++ ] = ParseAndSkipShort(&Ipr);
}
} else {
LineStart = 1;
LineEnd = 8;
}
TotalArgs += MemoryArgs[ServiceNumber];
if ( MemoryArgs[ServiceNumber] > InRegisterArgCount ) {
MemoryArgs[ServiceNumber] -= (CHAR)InRegisterArgCount;
} else {
MemoryArgs[ServiceNumber] = 0;
}
if ( DefFile ) {
fprintf(DefFile," Zw%s\n",OutputRecord);
fprintf(DefFile," Nt%s\n",OutputRecord);
} else {
for (Index1=LineStart; Index1<=LineEnd; Index1++) {
if (!TableFile) {
PrintStubLine(StubFile, Index1, UsrStbsFmtMacroName,
ServiceNumber, ArgIndex, Arguments, Braces);
if (Profile) {
PrintStubLine(ProfFile, Index1, UsrStbsFmtMacroName,
ServiceNumber, ArgIndex, Arguments, Braces);
if (Index1 == LineStart) {
fprintf(ProfTblFile,ProfTblFmt,
OutputRecord,
MemoryArgs[ServiceNumber]);
if (!strcmp(OutputRecord,
"QueryPerformanceCounter")) {
NapCounterServiceNumber = ServiceNumber;
}
}
}
} else {
PrintStubLine(StubFile, Index1, SysStbsFmtMacroName,
ServiceNumber, ArgIndex, Arguments, Braces);
}
}
}
//
// Generate table file entry and update service number.
//
if (TableFile != NULL) {
fprintf(TableFile,
TableEntryFmt,
InputRecord,
(MemoryArgs[ServiceNumber] ? 1 : 0 ),
MemoryArgs[ServiceNumber]);
}
ServiceNumber = ServiceNumber + 1;
}
if (TableFile == NULL) {
DebugFile = StubFile;
} else {
DebugFile = TableFile;
}
//
// Generate Error Return table if required.
// This table must be concatenated at the end of the system call service table.
//
if (ErrorReturnTable && (TableFile != NULL)) {
GenerateTable(TableFile, "ERRTBL", ServiceNumber, FALSE, Braces);
}
if (DispatchCount ) {
if ( Braces ) {
fprintf(DebugFile, "\n\nDECLARE_DISPATCH_COUNT( %d, %d )\n", ServiceNumber, TotalArgs);
} else {
fprintf(DebugFile, "\n\nDECLARE_DISPATCH_COUNT 0%xh, 0%xh\n", ServiceNumber, TotalArgs);
}
}
if (TableFile != NULL) {
//
// Generate highest service number.
//
if ( Braces )
fprintf(TableFile, "\nTABLE_END( %d )\n", ServiceNumber - 1);
else
fprintf(TableFile, "\nTABLE_END %d \n", ServiceNumber - 1);
//
// Generate number of arguments in memory table.
//
GenerateTable(TableFile, "ARGTBL", ServiceNumber, TRUE, Braces);
fclose(TableHeaderFile);
fclose(TableFile);
}
if (!DefFile) {
fprintf(StubFile, "\nSTUBS_END\n");
fclose(StubHeaderFile);
fclose(StubFile);
if (Profile) {
fprintf(ProfFile, "\nSTUBS_END\n");
fprintf(ProfTblFile, ProfTblSuffixFmt);
fprintf(ProfDotHFile, ProfDotHFmt, ServiceNumber);
fprintf(ProfIncFile, ProfIncFmt, NapCounterServiceNumber);
fclose(ProfHeaderFile);
fclose(ProfFile);
fclose(ProfDotHFile);
fclose(ProfTblFile);
}
}
fclose(InputFile);
//
// Clear the Archive bit for all the files created, since they are
// generated, there is no reason to back them up.
//
ClearArchiveBit(TableFileName);
ClearArchiveBit(StubFileName);
if (DefFile) {
ClearArchiveBit(DefFileData);
}
if (Profile) {
ClearArchiveBit(ProfFileName);
ClearArchiveBit(ProfDotHFileName);
ClearArchiveBit(ProfIncFileName);
ClearArchiveBit(ProfTblFileName);
}
return (0);
}
VOID
PrintStubLine (
FILE * pf,
SHORT Index1,
PCHAR pszMacro,
SHORT ServiceNumber,
SHORT ArgIndex,
SHORT *Arguments,
SHORT Braces
)
{
SHORT Index2;
fprintf(pf, pszMacro, Index1);
fprintf(pf, Braces ? "(" : " ");
fprintf(pf, StbFmtMacroArgs, ServiceNumber,
OutputRecord, MemoryArgs[ServiceNumber]);
for (Index2=0; Index2<ArgIndex; Index2++) {
fprintf(pf, ", %d", Arguments[Index2]);
}
fprintf(pf, Braces ? " )\n" : " \n");
}
SHORT
ParseAndSkipShort(
CHAR **ppBuffer
)
{
SHORT s = (SHORT)atoi(*ppBuffer);
while (**ppBuffer != '\n') {
if (*(*ppBuffer)++ == ',') {
break;
}
}
return s;
}
VOID
ClearArchiveBit(
PCHAR FileName
)
{
DWORD Attributes;
Attributes = GetFileAttributes(FileName);
if (Attributes != -1 && (Attributes & FILE_ATTRIBUTE_ARCHIVE)) {
SetFileAttributes(FileName, Attributes & ~FILE_ATTRIBUTE_ARCHIVE);
}
return;
}
VOID
GenerateTable(
FILE * pf,
PCHAR pszMacro,
SHORT ServiceNumber,
SHORT Args,
SHORT Braces
)
{
SHORT Index1, Index2, Limit, Value;
PCHAR pValues = (Args ? MemoryArgs : ErrorReturns);
fprintf(pf, "\n%s_BEGIN\n", pszMacro);
for (Index1 = 0; Index1 <= ServiceNumber - 1; Index1 += 8) {
fprintf(pf, "%s_ENTRY%s", pszMacro, Braces ? "(" : " ");
Limit = ServiceNumber - Index1 - 1;
if (Limit >= 7) {
Limit = 7;
}
for (Index2 = 0; Index2 <= Limit; Index2 += 1) {
Value = *(pValues + Index1 + Index2);
if (Args) {
Value *= 4;
}
fprintf(pf, Index2 == Limit ? "%d" : "%d,", Value);
}
if (Limit < 7) {
while(Index2 <= 7) {
fprintf(pf, ",0");
Index2++;
}
}
fprintf(pf, Braces ? ")\n" : " \n");
}
fprintf(pf, "\n%s_END\n", pszMacro);
}