1159 lines
25 KiB
C
1159 lines
25 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
genxx.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements a program which generates structure offset
|
||
|
definitions for kernel structures that are accessed in assembly code.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Forrest C. Foltz (forrestf) 20-Jan-98
|
||
|
|
||
|
|
||
|
To use:
|
||
|
|
||
|
This program reads an OBJ file generated by the target platform's
|
||
|
compiler.
|
||
|
|
||
|
To generate such an OBJ, go to ke\up and do a "nmake UMAPPL=gen<plt>",
|
||
|
where <plt> is a platform identifier like i386, etc.
|
||
|
|
||
|
All you need from this latter step is the OBJ, the link phase will not
|
||
|
succeed which is fine.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#define SKIP_M4
|
||
|
#include <genxx.h>
|
||
|
|
||
|
//
|
||
|
// Internal structure definitions, macros, constants
|
||
|
//
|
||
|
|
||
|
#define ARRAY_SIZE( x ) (sizeof( x ) / sizeof( (x)[0] ))
|
||
|
|
||
|
typedef struct _OUTPUT_FILE *POUTPUT_FILE;
|
||
|
typedef struct _OUTPUT_FILE {
|
||
|
POUTPUT_FILE Next;
|
||
|
ULONG EnableMask;
|
||
|
BOOLEAN IncFormat;
|
||
|
FILE *File;
|
||
|
} OUTPUT_FILE;
|
||
|
|
||
|
//
|
||
|
// Function prototypes follow
|
||
|
//
|
||
|
|
||
|
VOID
|
||
|
ApplyFixupsToImage( VOID );
|
||
|
|
||
|
VOID
|
||
|
BuildHeaderFiles(
|
||
|
STRUC_ELEMENT UNALIGNED *StrucArray
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
__cdecl
|
||
|
CheckCondition(
|
||
|
int Condition,
|
||
|
const char *format,
|
||
|
...
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
AddNewOutputFile(
|
||
|
PUCHAR RootRelativePath,
|
||
|
ULONG Flags
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
AddNewAbsoluteOutputFile(
|
||
|
PUCHAR AbsolutePath,
|
||
|
ULONG Flags
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
CloseOutputFiles( VOID );
|
||
|
|
||
|
VOID
|
||
|
_cdecl
|
||
|
HeaderPrint(
|
||
|
ULONG EnableFlags,
|
||
|
ULONG Type,
|
||
|
...
|
||
|
);
|
||
|
|
||
|
PSTRUC_ELEMENT
|
||
|
FindStructureElementArray(
|
||
|
PCHAR Buffer,
|
||
|
ULONG BufferSize
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
GetEnvironment( VOID );
|
||
|
|
||
|
PSTRUC_ELEMENT
|
||
|
LoadObjImage(
|
||
|
PUCHAR ImagePath
|
||
|
);
|
||
|
|
||
|
PCHAR
|
||
|
StripWhiteSpace(
|
||
|
PCHAR String
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
Usage( VOID );
|
||
|
|
||
|
//
|
||
|
// Constant tables follow
|
||
|
//
|
||
|
|
||
|
const char *PreprocessedFormatStringArray[] = {
|
||
|
|
||
|
// SEF_EQUATE
|
||
|
"#define %s 0x%0x\n",
|
||
|
|
||
|
// SEF_EQUATE64
|
||
|
"#define %s 0x%016I64x\n",
|
||
|
|
||
|
// SEF_COMMENT
|
||
|
"\n"
|
||
|
"//\n"
|
||
|
"// %s\n"
|
||
|
"//\n"
|
||
|
"\n",
|
||
|
|
||
|
// SEF_STRING
|
||
|
"%s\n",
|
||
|
|
||
|
// SEF_BITFLD
|
||
|
"#define %s_MASK 0x%I64x\n"
|
||
|
"#define %s 0x%0x\n",
|
||
|
|
||
|
// SEF_BITALIAS
|
||
|
"#define %s 0x%0x\n",
|
||
|
|
||
|
// SEF_STRUCTURE
|
||
|
"struct %s {\n"
|
||
|
" UCHAR fill[ %d ];\n"
|
||
|
"}; // %s\n"
|
||
|
|
||
|
};
|
||
|
|
||
|
const char *Asm386FormatStringArray[] = {
|
||
|
|
||
|
// SEF_EQUATE
|
||
|
"%s equ 0%04XH\n",
|
||
|
|
||
|
// SEF_EQUATE64
|
||
|
"%s equ 0%016I64XH\n",
|
||
|
|
||
|
// SEF_COMMENT
|
||
|
"\n"
|
||
|
";\n"
|
||
|
"; %s\n"
|
||
|
";\n"
|
||
|
"\n",
|
||
|
|
||
|
// SEF_STRING
|
||
|
"%s",
|
||
|
|
||
|
// SEF_BITFLD
|
||
|
"%s_MASK equ 0%I64XH\n"
|
||
|
"%s equ 0%0XH\n",
|
||
|
|
||
|
// SEF_BITALIAS
|
||
|
"%s equ 0%08XH\n",
|
||
|
|
||
|
// SEF_STRUCTURE
|
||
|
"%s struc\n"
|
||
|
" db %d dup(0)\n"
|
||
|
"%s ends\n"
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Each platform contains a list of generated header files.
|
||
|
//
|
||
|
|
||
|
typedef struct {
|
||
|
PCHAR HeaderPath;
|
||
|
ULONG Flags;
|
||
|
} HEADERPATH, *PHEADERPATH;
|
||
|
|
||
|
HEADERPATH HeaderListi386[] = {
|
||
|
{ "public\\sdk\\inc\\ks386.inc", SEF_KERNEL | SEF_INC_FORMAT },
|
||
|
{ "base\\ntos\\inc\\hal386.inc", SEF_HAL | SEF_INC_FORMAT },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
HEADERPATH HeaderListIa64[] = {
|
||
|
{ "public\\sdk\\inc\\ksia64.h", SEF_KERNEL | SEF_H_FORMAT },
|
||
|
{ "base\\ntos\\inc\\halia64.h", SEF_HAL | SEF_H_FORMAT },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
HEADERPATH HeaderListVdm[] = {
|
||
|
{ "public\\internal\\base\\inc\\vdmtib.inc", SEF_INC_FORMAT },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
HEADERPATH HeaderListAmd64[] = {
|
||
|
{ "public\\sdk\\inc\\ksamd64.inc", SEF_KERNEL | SEF_INC_FORMAT },
|
||
|
{ "base\\ntos\\inc\\halamd64.inc", SEF_HAL | SEF_INC_FORMAT },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
typedef struct {
|
||
|
PCHAR PlatformName;
|
||
|
PCHAR ObjPath;
|
||
|
PHEADERPATH HeaderPathList;
|
||
|
} PLATFORM, *PPLATFORM;
|
||
|
|
||
|
PLATFORM PlatformList[] = {
|
||
|
|
||
|
{ "i386",
|
||
|
"base\\ntos\\ke\\up\\obj\\i386\\geni386.obj",
|
||
|
HeaderListi386 },
|
||
|
|
||
|
{ "ia64",
|
||
|
"base\\ntos\\ke\\up\\obj\\ia64\\genia64.obj",
|
||
|
HeaderListIa64 },
|
||
|
|
||
|
{ "vdm",
|
||
|
"base\\ntos\\vdm\\up\\obj\\i386\\genvdm.obj",
|
||
|
HeaderListVdm },
|
||
|
|
||
|
{ "amd64",
|
||
|
"base\\ntos\\ke\\up\\obj\\amd64\\genamd64.obj",
|
||
|
HeaderListAmd64 },
|
||
|
|
||
|
{ NULL, NULL, NULL }
|
||
|
};
|
||
|
|
||
|
const char MarkerString[] = MARKER_STRING;
|
||
|
|
||
|
//
|
||
|
// Global vars follow
|
||
|
//
|
||
|
|
||
|
POUTPUT_FILE OutputFileList;
|
||
|
|
||
|
PCHAR ObjImage;
|
||
|
CHAR HalHeaderPath[ MAX_PATH ];
|
||
|
CHAR KernelHeaderPath[ MAX_PATH ];
|
||
|
CHAR HeaderPath[ MAX_PATH ];
|
||
|
CHAR ObjectPath[ MAX_PATH ];
|
||
|
CHAR NtRoot[ MAX_PATH ];
|
||
|
CHAR TempBuf[ MAX_PATH ];
|
||
|
BOOL fOutputSpecified;
|
||
|
BOOL fHalHeaderPath;
|
||
|
BOOL fKernelHeaderPath;
|
||
|
BOOL fIncFormat;
|
||
|
|
||
|
//
|
||
|
// The actual code...
|
||
|
//
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
main(
|
||
|
int argc,
|
||
|
char *argv[]
|
||
|
)
|
||
|
{
|
||
|
int argNum;
|
||
|
char *arg;
|
||
|
int platformIndex;
|
||
|
int fileIndex;
|
||
|
BOOL validSwitch;
|
||
|
PSTRUC_ELEMENT strucArray;
|
||
|
PPLATFORM platform;
|
||
|
PHEADERPATH headerPath;
|
||
|
|
||
|
GetEnvironment();
|
||
|
|
||
|
//
|
||
|
// Assume no platform specified, then see if we can find one.
|
||
|
//
|
||
|
|
||
|
ObjectPath[ 0 ] = '\0';
|
||
|
for( argNum = 1; argNum < argc; argNum++ ){
|
||
|
|
||
|
validSwitch = FALSE;
|
||
|
|
||
|
arg = argv[ argNum ];
|
||
|
if( *arg == '/' || *arg == '-' ){
|
||
|
|
||
|
//
|
||
|
// A switch was passed. See what it is.
|
||
|
//
|
||
|
|
||
|
arg++;
|
||
|
|
||
|
switch( *arg ){
|
||
|
|
||
|
case 'o':
|
||
|
|
||
|
//
|
||
|
// Specified an output file
|
||
|
//
|
||
|
|
||
|
fOutputSpecified = TRUE;
|
||
|
strcpy( HeaderPath, arg+1 );
|
||
|
validSwitch = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
|
||
|
//
|
||
|
// Specified include file suffix (either 'h' or 'inc')
|
||
|
//
|
||
|
|
||
|
if( _stricmp( arg+1, "inc" ) == 0 ){
|
||
|
|
||
|
//
|
||
|
// We would like the "inc" format, thanks
|
||
|
//
|
||
|
|
||
|
fIncFormat = TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
CheckCondition( _stricmp( arg+1, "h" ) == 0,
|
||
|
"Invalid suffix option: -s[inc|h]\n");
|
||
|
}
|
||
|
validSwitch = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'k':
|
||
|
|
||
|
//
|
||
|
// Kernel header path. Save off.
|
||
|
//
|
||
|
fKernelHeaderPath = TRUE;
|
||
|
strcpy( KernelHeaderPath, arg+1 );
|
||
|
validSwitch = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'h':
|
||
|
|
||
|
//
|
||
|
// Hal header path. Save off.
|
||
|
//
|
||
|
fHalHeaderPath = TRUE;
|
||
|
strcpy( HalHeaderPath, arg+1 );
|
||
|
validSwitch = TRUE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
// Check our platform list.
|
||
|
//
|
||
|
|
||
|
platform = PlatformList;
|
||
|
while( platform->PlatformName != NULL ){
|
||
|
|
||
|
if( _stricmp( platform->PlatformName,
|
||
|
arg ) == 0 ){
|
||
|
|
||
|
//
|
||
|
// Platform was specified, we will build the path to
|
||
|
// the obj.
|
||
|
//
|
||
|
|
||
|
sprintf( ObjectPath,
|
||
|
"%s\\%s",
|
||
|
NtRoot,
|
||
|
platform->ObjPath );
|
||
|
|
||
|
//
|
||
|
// Add the header paths too.
|
||
|
//
|
||
|
|
||
|
headerPath = platform->HeaderPathList;
|
||
|
while( headerPath->HeaderPath != NULL ){
|
||
|
|
||
|
if (fHalHeaderPath && (headerPath->Flags & SEF_HAL)) {
|
||
|
strcpy(TempBuf, HalHeaderPath);
|
||
|
AddNewAbsoluteOutputFile( HalHeaderPath, headerPath->Flags );
|
||
|
} else
|
||
|
if (fKernelHeaderPath && (headerPath->Flags & SEF_KERNEL)) {
|
||
|
strcpy(TempBuf, KernelHeaderPath);
|
||
|
AddNewAbsoluteOutputFile( KernelHeaderPath, headerPath->Flags );
|
||
|
} else {
|
||
|
AddNewOutputFile( headerPath->HeaderPath,
|
||
|
headerPath->Flags );
|
||
|
}
|
||
|
|
||
|
headerPath++;
|
||
|
}
|
||
|
|
||
|
validSwitch = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
platform++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( validSwitch == FALSE ){
|
||
|
Usage();
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// We are dealing with something that is not a switch. The only
|
||
|
// possibility is the path to the object file.
|
||
|
//
|
||
|
|
||
|
strcpy( ObjectPath, arg );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CheckCondition( ObjectPath[0] != '\0',
|
||
|
"Object path not specified\n" );
|
||
|
|
||
|
if( fOutputSpecified != FALSE ){
|
||
|
|
||
|
//
|
||
|
// The output path was specified
|
||
|
//
|
||
|
|
||
|
AddNewAbsoluteOutputFile( HeaderPath,
|
||
|
fIncFormat ? SEF_INC_FORMAT : SEF_H_FORMAT );
|
||
|
}
|
||
|
|
||
|
strucArray = LoadObjImage( ObjectPath );
|
||
|
|
||
|
BuildHeaderFiles( strucArray );
|
||
|
|
||
|
CloseOutputFiles();
|
||
|
|
||
|
//
|
||
|
// Indicate success.
|
||
|
//
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddNewAbsoluteOutputFile(
|
||
|
PUCHAR AbsolutePath,
|
||
|
ULONG Flags
|
||
|
)
|
||
|
{
|
||
|
POUTPUT_FILE outputFile;
|
||
|
|
||
|
outputFile = malloc( sizeof( OUTPUT_FILE ));
|
||
|
CheckCondition( outputFile != NULL, "Out of memory\n" );
|
||
|
|
||
|
outputFile->EnableMask = (ULONG)(Flags & SEF_ENABLE_MASK);
|
||
|
|
||
|
if( (Flags & SEF_INC_FORMAT_MASK) == SEF_INC_FORMAT ){
|
||
|
|
||
|
//
|
||
|
// This file will be created in '.inc' format for the 386 assembler.
|
||
|
//
|
||
|
|
||
|
outputFile->IncFormat = TRUE;
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// This file will be created in '.h' format for the standard C
|
||
|
// preprocessor.
|
||
|
//
|
||
|
|
||
|
outputFile->IncFormat = FALSE;
|
||
|
}
|
||
|
|
||
|
outputFile->File = fopen( AbsolutePath, "w" );
|
||
|
CheckCondition( outputFile->File != NULL,
|
||
|
"Cannot open %s for writing.\n",
|
||
|
TempBuf );
|
||
|
|
||
|
printf("%s -> %s\n", ObjectPath, TempBuf );
|
||
|
|
||
|
//
|
||
|
// Link this structure into the list of output files
|
||
|
//
|
||
|
|
||
|
outputFile->Next = OutputFileList;
|
||
|
OutputFileList = outputFile;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddNewOutputFile(
|
||
|
PUCHAR RootRelativePath,
|
||
|
ULONG Flags
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Create the canonoical file path and open the file.
|
||
|
//
|
||
|
|
||
|
sprintf( TempBuf,
|
||
|
"%s\\%s",
|
||
|
NtRoot,
|
||
|
RootRelativePath );
|
||
|
|
||
|
AddNewAbsoluteOutputFile( TempBuf, Flags );
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CloseOutputFiles( VOID )
|
||
|
{
|
||
|
POUTPUT_FILE outputFile;
|
||
|
|
||
|
outputFile = OutputFileList;
|
||
|
while( outputFile != NULL ){
|
||
|
|
||
|
fclose( outputFile->File );
|
||
|
outputFile = outputFile->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
PSTRUC_ELEMENT
|
||
|
LoadObjImage(
|
||
|
PUCHAR ImagePath
|
||
|
)
|
||
|
{
|
||
|
long objImageSize;
|
||
|
int result;
|
||
|
PSTRUC_ELEMENT strucArray;
|
||
|
FILE * objFile;
|
||
|
|
||
|
//
|
||
|
// Open up and read the platform-specific .obj file.
|
||
|
//
|
||
|
|
||
|
objFile = fopen( ImagePath, "rb" );
|
||
|
CheckCondition( objFile != NULL,
|
||
|
"Cannot open %s for reading.\n"
|
||
|
"This file must have been created by the compiler for the "
|
||
|
"target platform.\n",
|
||
|
ImagePath );
|
||
|
|
||
|
//
|
||
|
// Get the file size, allocate a buffer, read it in, and close.
|
||
|
//
|
||
|
|
||
|
result = fseek( objFile, 0, SEEK_END );
|
||
|
CheckCondition( result == 0,
|
||
|
"fseek() failed, error %d\n",
|
||
|
errno );
|
||
|
|
||
|
objImageSize = ftell( objFile );
|
||
|
CheckCondition( objImageSize != -1L,
|
||
|
"ftell() failed, error %d\n",
|
||
|
errno );
|
||
|
|
||
|
CheckCondition( objImageSize > 0,
|
||
|
"%s appears to be corrupt\n",
|
||
|
ImagePath );
|
||
|
|
||
|
ObjImage = malloc( objImageSize );
|
||
|
CheckCondition( ObjImage != NULL,
|
||
|
"Out of memory\n" );
|
||
|
|
||
|
result = fseek( objFile, 0, SEEK_SET );
|
||
|
CheckCondition( result == 0,
|
||
|
"fseek() failed, error %d\n",
|
||
|
errno );
|
||
|
|
||
|
result = fread( ObjImage, 1, objImageSize, objFile );
|
||
|
CheckCondition( result == objImageSize,
|
||
|
"Error reading from %s\n",
|
||
|
ImagePath );
|
||
|
|
||
|
fclose( objFile );
|
||
|
|
||
|
//
|
||
|
// Even though this is just an .obj file, we want it "fixed up"
|
||
|
//
|
||
|
|
||
|
ApplyFixupsToImage();
|
||
|
|
||
|
//
|
||
|
// Got the image, find the beginning of the array.
|
||
|
//
|
||
|
|
||
|
strucArray = FindStructureElementArray( ObjImage,
|
||
|
objImageSize );
|
||
|
CheckCondition( strucArray != NULL,
|
||
|
"%s does not contain a structure description array.\n",
|
||
|
ImagePath );
|
||
|
|
||
|
return strucArray;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BuildHeaderFiles(
|
||
|
STRUC_ELEMENT UNALIGNED *StrucArray
|
||
|
)
|
||
|
{
|
||
|
STRUC_ELEMENT UNALIGNED *strucArray;
|
||
|
ULONG runningEnableMask;
|
||
|
ULONG enableMask;
|
||
|
ULONG sefType;
|
||
|
const char *formatString;
|
||
|
ULONG bitFieldStart;
|
||
|
PUINT64 bitFieldPtr;
|
||
|
UINT64 bitFieldData;
|
||
|
PCHAR name;
|
||
|
BOOLEAN finished;
|
||
|
|
||
|
//
|
||
|
// Process each element in the array. The first element is the
|
||
|
// marker string element, so it is skipped.
|
||
|
//
|
||
|
|
||
|
runningEnableMask = 0;
|
||
|
finished = FALSE;
|
||
|
strucArray = StrucArray;
|
||
|
|
||
|
do{
|
||
|
strucArray++;
|
||
|
|
||
|
sefType = (ULONG)(strucArray->Flags & SEF_TYPE_MASK);
|
||
|
|
||
|
if( sefType == SEF_BITFLD ){
|
||
|
|
||
|
//
|
||
|
// For bitfields, the enable mask is set explicitly
|
||
|
//
|
||
|
|
||
|
enableMask = (ULONG)(strucArray->Flags & SEF_ENABLE_MASK);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// For everything else, we use the current runningEnableMask
|
||
|
//
|
||
|
|
||
|
enableMask = runningEnableMask;
|
||
|
}
|
||
|
|
||
|
switch( sefType ){
|
||
|
|
||
|
case SEF_BITFLD:
|
||
|
|
||
|
//
|
||
|
// This kind of element is tricky. "Equate" is actually a
|
||
|
// pointer to a bitfield structure. This structure has had
|
||
|
// a portion of it (the bitfield) initialized to ones.
|
||
|
//
|
||
|
// It is the job of this case to poke around in that
|
||
|
// structure in order to determine where the bitfield landed.
|
||
|
//
|
||
|
|
||
|
bitFieldPtr = (PINT64)(strucArray->Equate);
|
||
|
bitFieldData = *bitFieldPtr;
|
||
|
|
||
|
//
|
||
|
// Determine the zero-based starting bitnumber of the field.
|
||
|
//
|
||
|
|
||
|
bitFieldStart = 0;
|
||
|
while( (bitFieldData & ((UINT64)1 << bitFieldStart)) == 0 ){
|
||
|
|
||
|
bitFieldStart++;
|
||
|
}
|
||
|
|
||
|
name = StripWhiteSpace( strucArray->Name );
|
||
|
|
||
|
if( *name != '\0'){
|
||
|
|
||
|
HeaderPrint( enableMask,
|
||
|
sefType,
|
||
|
name,
|
||
|
bitFieldData,
|
||
|
name,
|
||
|
bitFieldStart );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// A bitfield can be followed by any number of
|
||
|
// SEF_BITALIAS entries. These are alias names for the
|
||
|
// bitmask that was just defined.
|
||
|
//
|
||
|
|
||
|
while( TRUE ){
|
||
|
|
||
|
sefType = (ULONG)((strucArray+1)->Flags & SEF_TYPE_MASK);
|
||
|
if( sefType != SEF_BITALIAS ){
|
||
|
|
||
|
//
|
||
|
// No more aliases.
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This is a bitmask alias field, process it.
|
||
|
//
|
||
|
|
||
|
strucArray++;
|
||
|
|
||
|
name = StripWhiteSpace( strucArray->Name );
|
||
|
|
||
|
HeaderPrint( enableMask,
|
||
|
sefType,
|
||
|
name,
|
||
|
bitFieldData );
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SEF_END:
|
||
|
finished = TRUE;
|
||
|
break;
|
||
|
|
||
|
case SEF_EQUATE:
|
||
|
|
||
|
if( (LONG64)strucArray->Equate < 0 ){
|
||
|
|
||
|
//
|
||
|
// Negative constant
|
||
|
//
|
||
|
|
||
|
if( (LONG64)strucArray->Equate < LONG_MIN ){
|
||
|
|
||
|
//
|
||
|
// More negative than can be represented in 32 bits
|
||
|
//
|
||
|
|
||
|
sefType = SEF_EQUATE64;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Falls within [LONG_MIN..0], Leave as SEF_EQUATE32
|
||
|
//
|
||
|
}
|
||
|
|
||
|
} else if( (ULONG64)strucArray->Equate > (ULONG_MAX) ){
|
||
|
|
||
|
//
|
||
|
// More positive than can be represented in 32 bits
|
||
|
//
|
||
|
|
||
|
sefType = SEF_EQUATE64;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fall through
|
||
|
//
|
||
|
|
||
|
case SEF_EQUATE64:
|
||
|
case SEF_COMMENT:
|
||
|
HeaderPrint( enableMask,
|
||
|
sefType,
|
||
|
strucArray->Name,
|
||
|
(UINT64)strucArray->Equate );
|
||
|
break;
|
||
|
|
||
|
case SEF_STRING:
|
||
|
HeaderPrint( enableMask,
|
||
|
sefType,
|
||
|
strucArray->Name,
|
||
|
strucArray->Equate );
|
||
|
break;
|
||
|
|
||
|
case SEF_STRUCTURE:
|
||
|
HeaderPrint( enableMask,
|
||
|
sefType,
|
||
|
strucArray->Name,
|
||
|
(ULONG)strucArray->Equate,
|
||
|
strucArray->Name );
|
||
|
break;
|
||
|
|
||
|
case SEF_SETMASK:
|
||
|
runningEnableMask |= strucArray->Equate;
|
||
|
break;
|
||
|
|
||
|
case SEF_CLRMASK:
|
||
|
runningEnableMask &= ~strucArray->Equate;
|
||
|
break;
|
||
|
|
||
|
case SEF_PATH:
|
||
|
|
||
|
//
|
||
|
// Add another output file to our list.
|
||
|
//
|
||
|
|
||
|
CheckCondition( fOutputSpecified == FALSE,
|
||
|
"setPath() in %s incompatible with -o flag\n",
|
||
|
ObjectPath );
|
||
|
|
||
|
AddNewOutputFile( strucArray->Name,
|
||
|
(ULONG)strucArray->Flags );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
// Found an SEF_TYPE we don't know about. This is fatal.
|
||
|
//
|
||
|
|
||
|
CheckCondition( FALSE,
|
||
|
"Unknown structure type %d. "
|
||
|
"Need an updated genxx.exe?\n",
|
||
|
sefType );
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
} while( finished == FALSE );
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
__cdecl
|
||
|
CheckCondition(
|
||
|
int Condition,
|
||
|
const char *FormatString,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
va_list(arglist);
|
||
|
|
||
|
va_start(arglist, FormatString);
|
||
|
|
||
|
if( Condition == 0 ){
|
||
|
|
||
|
//
|
||
|
// A fatal error was encountered. Bail.
|
||
|
//
|
||
|
|
||
|
vprintf( FormatString, arglist );
|
||
|
perror( "genxx" );
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
_cdecl
|
||
|
HeaderPrint(
|
||
|
ULONG EnableFlags,
|
||
|
ULONG Type,
|
||
|
...
|
||
|
)
|
||
|
{
|
||
|
POUTPUT_FILE outputFile;
|
||
|
char const *formatString;
|
||
|
|
||
|
va_list arglist;
|
||
|
|
||
|
//
|
||
|
// Send the output to each output file as appropriate
|
||
|
//
|
||
|
|
||
|
outputFile = OutputFileList;
|
||
|
while( outputFile != NULL ){
|
||
|
|
||
|
va_start( arglist, Type );
|
||
|
|
||
|
if( outputFile->EnableMask == 0 ||
|
||
|
(outputFile->EnableMask & EnableFlags) != 0 ){
|
||
|
|
||
|
//
|
||
|
// Either this output file gets everything, or the mask
|
||
|
// matches. Figure out which format to use... '.h' or '.inc'
|
||
|
// style.
|
||
|
//
|
||
|
|
||
|
if( Type == SEF_STRING ){
|
||
|
|
||
|
//
|
||
|
// For SEF_STRING, strucArray->Name *is* the format string.
|
||
|
//
|
||
|
|
||
|
formatString = va_arg( arglist, PUCHAR );
|
||
|
|
||
|
} else if( outputFile->IncFormat != FALSE ){
|
||
|
|
||
|
//
|
||
|
// Use the ".inc" format
|
||
|
//
|
||
|
|
||
|
formatString = Asm386FormatStringArray[ Type ];
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Use the ".h" format
|
||
|
//
|
||
|
|
||
|
formatString = PreprocessedFormatStringArray[ Type ];
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now send it
|
||
|
//
|
||
|
|
||
|
vfprintf( outputFile->File, formatString, arglist );
|
||
|
}
|
||
|
|
||
|
va_end( arglist );
|
||
|
|
||
|
//
|
||
|
// Process all current output files.
|
||
|
//
|
||
|
|
||
|
outputFile = outputFile->Next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
GetEnvironment( VOID )
|
||
|
{
|
||
|
char *ntDrive;
|
||
|
char *ntRoot;
|
||
|
|
||
|
//
|
||
|
// Set NtRoot = %_NTDRIVE%\%_NTROOT%
|
||
|
//
|
||
|
|
||
|
ntDrive = getenv( "_NTDRIVE" );
|
||
|
ntRoot = getenv( "_NTROOT" );
|
||
|
if( ntDrive != NULL && ntRoot != NULL ){
|
||
|
|
||
|
sprintf( NtRoot, "%s%s", ntDrive, ntRoot );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// If either _NTDRIVE or _NTROOT were not found in the environment,
|
||
|
// let's try with \nt.
|
||
|
//
|
||
|
|
||
|
strcpy( NtRoot, "\\nt" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PSTRUC_ELEMENT
|
||
|
FindStructureElementArray(
|
||
|
PCHAR Buffer,
|
||
|
ULONG BufferSize
|
||
|
)
|
||
|
{
|
||
|
PCHAR searchPoint;
|
||
|
PCHAR searchEndPoint;
|
||
|
PSTRUC_ELEMENT strucElement;
|
||
|
|
||
|
//
|
||
|
// Search Buffer for the beginning of a structure element array.
|
||
|
// The first element in this array contains MARKER_STRING.
|
||
|
//
|
||
|
|
||
|
searchPoint = Buffer;
|
||
|
searchEndPoint = Buffer + BufferSize - sizeof( MarkerString );
|
||
|
|
||
|
do{
|
||
|
//
|
||
|
// We scan the buffer a character at a time until we find a character
|
||
|
// that matches the first character in MarkerString.
|
||
|
//
|
||
|
|
||
|
if( *searchPoint != MarkerString[ 0 ] ){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// When a matching char is found, the rest of the string is compared.
|
||
|
//
|
||
|
|
||
|
if( strcmp( searchPoint, MarkerString ) == 0 ){
|
||
|
|
||
|
//
|
||
|
// It matched too, we're done.
|
||
|
//
|
||
|
|
||
|
strucElement = CONTAINING_RECORD( searchPoint,
|
||
|
STRUC_ELEMENT,
|
||
|
Name );
|
||
|
return strucElement;
|
||
|
}
|
||
|
|
||
|
} while( searchPoint++ < searchEndPoint );
|
||
|
|
||
|
//
|
||
|
// Fell out of the loop, we couldn't find the string.
|
||
|
//
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
Usage( VOID ){
|
||
|
|
||
|
int platformIndex;
|
||
|
PPLATFORM platform;
|
||
|
|
||
|
|
||
|
printf("genxx: [");
|
||
|
platform = PlatformList;
|
||
|
while( platform->PlatformName != NULL ){
|
||
|
|
||
|
printf("-%s|", platform->PlatformName );
|
||
|
platform++;
|
||
|
}
|
||
|
|
||
|
printf("<objpath>] [-s<h|inc>] [-o<outputpath>]\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ApplyFixupsToImage( VOID )
|
||
|
{
|
||
|
//
|
||
|
// Applies fixups to the OBJ image loaded at ObjImage
|
||
|
//
|
||
|
|
||
|
PIMAGE_FILE_HEADER fileHeader;
|
||
|
PIMAGE_SECTION_HEADER sectionHeader;
|
||
|
PIMAGE_SECTION_HEADER sectionHeaderArray;
|
||
|
PIMAGE_SYMBOL symbolTable;
|
||
|
PIMAGE_SYMBOL symbol;
|
||
|
PIMAGE_RELOCATION reloc;
|
||
|
PIMAGE_RELOCATION relocArray;
|
||
|
ULONG sectionNum;
|
||
|
ULONG relocNum;
|
||
|
ULONG_PTR targetVa;
|
||
|
PULONG_PTR fixupVa;
|
||
|
|
||
|
fileHeader = (PIMAGE_FILE_HEADER)ObjImage;
|
||
|
|
||
|
//
|
||
|
// We need the symbol table to apply the fixups
|
||
|
//
|
||
|
|
||
|
symbolTable = (PIMAGE_SYMBOL)(ObjImage + fileHeader->PointerToSymbolTable);
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the first element in the section header
|
||
|
//
|
||
|
|
||
|
sectionHeaderArray = (PIMAGE_SECTION_HEADER)(ObjImage +
|
||
|
sizeof( IMAGE_FILE_HEADER ) +
|
||
|
fileHeader->SizeOfOptionalHeader);
|
||
|
|
||
|
//
|
||
|
// Apply the fixups for each section
|
||
|
//
|
||
|
|
||
|
for( sectionNum = 0;
|
||
|
sectionNum < fileHeader->NumberOfSections;
|
||
|
sectionNum++ ){
|
||
|
|
||
|
sectionHeader = §ionHeaderArray[ sectionNum ];
|
||
|
|
||
|
if (memcmp(sectionHeader->Name, ".data", sizeof(".data")+1)) {
|
||
|
// Not .data - don't bother with the fixup
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Apply each fixup in this section
|
||
|
//
|
||
|
|
||
|
relocArray = (PIMAGE_RELOCATION)(ObjImage +
|
||
|
sectionHeader->PointerToRelocations);
|
||
|
for( relocNum = 0;
|
||
|
relocNum < sectionHeader->NumberOfRelocations;
|
||
|
relocNum++ ){
|
||
|
|
||
|
reloc = &relocArray[ relocNum ];
|
||
|
|
||
|
//
|
||
|
// The relocation gives us the position in the image of the
|
||
|
// relocation modification (VirtualAddress). To find out what
|
||
|
// to put there, we have to look the symbol up in the symbol index.
|
||
|
//
|
||
|
|
||
|
symbol = &symbolTable[ reloc->SymbolTableIndex ];
|
||
|
|
||
|
targetVa =
|
||
|
sectionHeaderArray[ symbol->SectionNumber-1 ].PointerToRawData;
|
||
|
|
||
|
targetVa += symbol->Value;
|
||
|
targetVa += (ULONG_PTR)ObjImage;
|
||
|
|
||
|
fixupVa = (PULONG_PTR)(ObjImage +
|
||
|
reloc->VirtualAddress +
|
||
|
sectionHeader->PointerToRawData );
|
||
|
|
||
|
*fixupVa = targetVa;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
IsWhiteSpace(
|
||
|
CHAR Char
|
||
|
)
|
||
|
{
|
||
|
if( Char == '\t' ||
|
||
|
Char == ' ' ||
|
||
|
Char == '\r' ||
|
||
|
Char == '\n' ){
|
||
|
|
||
|
return TRUE;
|
||
|
} else {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PCHAR
|
||
|
StripWhiteSpace(
|
||
|
PCHAR String
|
||
|
)
|
||
|
{
|
||
|
PCHAR chr;
|
||
|
ULONG strLen;
|
||
|
|
||
|
strLen = strlen( String );
|
||
|
if( strLen == 0 ){
|
||
|
return String;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Strip off trailing whitespace
|
||
|
//
|
||
|
|
||
|
chr = String + strLen - 1;
|
||
|
while( IsWhiteSpace( *chr )){
|
||
|
*chr = '\0';
|
||
|
chr--;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Advance past leading whitespace
|
||
|
//
|
||
|
|
||
|
chr = String;
|
||
|
while( IsWhiteSpace( *chr )){
|
||
|
chr++;
|
||
|
}
|
||
|
|
||
|
return chr;
|
||
|
}
|
||
|
|