mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1230 lines
29 KiB
1230 lines
29 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1990-1992 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
uixport.c
|
|
This program parses the output of the "COFF -DUMP -SYMBOLS" command
|
|
and extract all public symbols. This is used to generate .DEF files
|
|
for DLLs.
|
|
|
|
|
|
FILE HISTORY:
|
|
KeithMo 09-Aug-1992 00.00.00 Created.
|
|
KeithMo 14-Sep-1992 00.00.01 Strip stdcall decoration from symbols.
|
|
KeithMo 16-Oct-1992 00.00.02 Handle goofy []()* in coff output.
|
|
|
|
DavidHov 18-Sep-1993 00.00.04 Added exclusion list processing.
|
|
The exlusion list is generated
|
|
mechanically and constiutes all the
|
|
symbols which are not imported
|
|
by any known NETUI/RAS/MAC (et al.)
|
|
binary.
|
|
|
|
DavidHov 22-Sep-1993 00.00.05 Added symbol ignore table and logic.
|
|
The ignore table at this time ignores
|
|
only the gigantic symbols generated
|
|
by C8 when /Gf is used; these names
|
|
are strings which are to be merged
|
|
at link time.
|
|
|
|
DaveWolfe 06-Jul-1994 00.01.01 (Motorola) Added -ppc option for
|
|
PowerPC to strip entry point symbols
|
|
generated for PPC TOC.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <search.h>
|
|
|
|
|
|
//
|
|
// This is the maximum length (in characters) of any line we'll
|
|
// receive from COFF. If we receive a longer line, the program
|
|
// won't crash, but we may miss a public symbol.
|
|
//
|
|
|
|
#define MAX_LINE_FROM_COFF 2000
|
|
|
|
//
|
|
// This is the maximum length (in characters) of any symbol we'll
|
|
// receive from COFF.
|
|
//
|
|
|
|
#define MAX_SYMBOL 247
|
|
|
|
//
|
|
// This is the maximum length (in characters) of any error message
|
|
// we'll display.
|
|
//
|
|
|
|
#define MAX_ERROR_MESSAGE 256
|
|
|
|
//
|
|
// This is the length (in characters) of the header->output copy buffer.
|
|
//
|
|
|
|
#define HEADER_COPY_BUFFER_SIZE 256
|
|
|
|
|
|
|
|
//
|
|
// Messages.
|
|
//
|
|
|
|
char _szBanner[] = "%s version 00.01.01\n";
|
|
char _szCannotOpenForRead[] = "Cannot open %s for read access.";
|
|
char _szCannotOpenForWrite[] = "Cannot open %s for write access.";
|
|
char _szErrorCopyingHeader[] = "Error copying header to output.";
|
|
char _szInvalidSwitch[] = "Invalid switch '%c'.\n\n";
|
|
char _szSymbolTooLong[] = "Symbol %s exceeds max symbol length!\n";
|
|
char _szExclusionError[] = "Error processing exclusion list file; ignored" ;
|
|
char _szExclusionEmpty[] = "Exclusion list file specified is empty; ignored" ;
|
|
|
|
|
|
//
|
|
// Globals.
|
|
//
|
|
|
|
char * _pszProgramName;
|
|
FILE * _fileIn;
|
|
FILE * _fileOut;
|
|
FILE * _fileHeader;
|
|
int _fStripLeadingUnderscore;
|
|
int _fNukeStdcallDecoration;
|
|
int _fPowerPC;
|
|
int _fIA64;
|
|
|
|
char * _pszExclusionListFile = NULL ;
|
|
void * _pvExclusionBlock = NULL ;
|
|
char * * _apszExclusionArray = NULL ;
|
|
int _cExclusionItems = -1 ;
|
|
int _cExcludedItems = 0 ;
|
|
int _cIgnoredItems = 0 ;
|
|
|
|
|
|
// This table contains the prefixes of symbol names to ignore
|
|
// while building the DEF file. See ValidSymbol().
|
|
|
|
static char * apszIgnore [] =
|
|
{
|
|
"??_C@_", // Ignore generated string symbol names
|
|
NULL
|
|
};
|
|
|
|
|
|
//
|
|
// Prototypes.
|
|
//
|
|
|
|
int __cdecl main( int cArgs,
|
|
char * pArgs[] );
|
|
|
|
void Cleanup( void );
|
|
|
|
void CopyHeaderToOutput( FILE * fHeader,
|
|
FILE * fOutput );
|
|
|
|
int ExtractSymbol( char * pszLineFromCoff,
|
|
char * pszSymbol );
|
|
|
|
void __cdecl FatalError( int err,
|
|
char * pszFmt,
|
|
... );
|
|
|
|
void __cdecl NonFatalError( char * pszFmt,
|
|
... );
|
|
|
|
int IsHexNumber( char * pszHexNumber );
|
|
|
|
char * NoPath( char * pszPathName );
|
|
|
|
void ProcessCommandLine( int cArgs,
|
|
char * pArgs[] );
|
|
|
|
void StripStdcallDecoration( char * pszSymbol );
|
|
|
|
void Usage( void );
|
|
|
|
// Create the exclusion list.
|
|
|
|
int CreateExclusionList ( char * pszFileName,
|
|
void * * pvData,
|
|
char * * * apszStrings ) ;
|
|
|
|
// Check the excluded symbol list for this name
|
|
|
|
int ExcludedSymbol ( char * pszSymbol ) ;
|
|
|
|
int ValidSymbol ( const char * psz ) ;
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: main
|
|
|
|
SYNOPSIS: C program entrypoint.
|
|
|
|
ENTRY: cArgs - Number of command line arguments.
|
|
|
|
pArgs - An array of pointers to the
|
|
command line arguments.
|
|
|
|
RETURNS: int - 0 if everything ran OK,
|
|
!0 if an error occurred.
|
|
|
|
NOTES: See the Usage() function for valid command line arguments.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
KeithMo 14-Sep-1992 Strip stdcall decoration from symbols.
|
|
|
|
********************************************************************/
|
|
int __cdecl main( int cArgs,
|
|
char * pArgs[] )
|
|
{
|
|
//
|
|
// A line read from COFF.
|
|
//
|
|
|
|
char szLineFromCoff[MAX_LINE_FROM_COFF+1];
|
|
|
|
//
|
|
// A symbol extracted from the COFF line.
|
|
//
|
|
|
|
char szSymbol[MAX_SYMBOL+1];
|
|
|
|
//
|
|
// Get the program name, for our messages.
|
|
//
|
|
|
|
_pszProgramName = NoPath( pArgs[0] );
|
|
|
|
//
|
|
// Announce ourselves.
|
|
//
|
|
|
|
fprintf( stderr,
|
|
_szBanner,
|
|
_pszProgramName );
|
|
|
|
//
|
|
// Parse the command line arguments.
|
|
//
|
|
|
|
ProcessCommandLine( cArgs, pArgs );
|
|
|
|
//
|
|
// If requested, copy the header file before processing
|
|
// the COFF output.
|
|
//
|
|
|
|
if( _fileHeader != NULL )
|
|
{
|
|
CopyHeaderToOutput( _fileHeader, _fileOut );
|
|
}
|
|
|
|
//
|
|
// If an exclusion list file was specified, process it.
|
|
// If it's empty, ignore it.
|
|
//
|
|
|
|
if ( _pszExclusionListFile )
|
|
{
|
|
_cExclusionItems = CreateExclusionList( _pszExclusionListFile,
|
|
& _pvExclusionBlock,
|
|
& _apszExclusionArray ) ;
|
|
|
|
if ( _cExclusionItems < 0 )
|
|
{
|
|
_pszExclusionListFile = NULL ;
|
|
NonFatalError( _szExclusionError ) ;
|
|
}
|
|
else
|
|
if ( _cExclusionItems == 0 )
|
|
{
|
|
_pszExclusionListFile = NULL ;
|
|
NonFatalError( _szExclusionEmpty ) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read the lines from coff, extract the symbols, and
|
|
// write them to the output file.
|
|
//
|
|
|
|
while( fgets( szLineFromCoff, MAX_LINE_FROM_COFF, _fileIn ) != NULL )
|
|
{
|
|
char * pszDisplay = szSymbol;
|
|
|
|
if( !ExtractSymbol( szLineFromCoff, szSymbol ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( ! _fNukeStdcallDecoration )
|
|
{
|
|
StripStdcallDecoration( szSymbol );
|
|
}
|
|
|
|
if ( ! ValidSymbol( pszDisplay ) )
|
|
{
|
|
_cIgnoredItems++ ;
|
|
continue ;
|
|
}
|
|
|
|
if ( _pszExclusionListFile && ExcludedSymbol( szSymbol ) )
|
|
{
|
|
_cExcludedItems++ ;
|
|
continue ;
|
|
}
|
|
|
|
if( _fStripLeadingUnderscore && ( *pszDisplay == '_' ) )
|
|
{
|
|
pszDisplay++;
|
|
}
|
|
|
|
fprintf( _fileOut, "%s\n", pszDisplay );
|
|
}
|
|
|
|
fprintf( _fileOut, "\032" );
|
|
|
|
// Give a synopsis of exclusion file processesing.
|
|
|
|
fprintf( stdout, "\nSymbols ignored: %ld\n", _cIgnoredItems ) ;
|
|
|
|
if ( _pszExclusionListFile )
|
|
{
|
|
fprintf( stdout, "\nExcluded symbols registered: %ld, excluded: %ld\n",
|
|
_cExclusionItems, _cExcludedItems ) ;
|
|
}
|
|
|
|
//
|
|
// Cleanup any open files, then exit.
|
|
//
|
|
|
|
Cleanup();
|
|
return 0;
|
|
|
|
} // main
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: Cleanup
|
|
|
|
SYNOPSIS: Cleanup the app just before termination. Closes any
|
|
open files, frees memory buffers, etc.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
|
|
********************************************************************/
|
|
void Cleanup( void )
|
|
{
|
|
if( _fileHeader != NULL )
|
|
{
|
|
fclose( _fileHeader );
|
|
}
|
|
|
|
if( _fileIn != stdin )
|
|
{
|
|
fclose( _fileIn );
|
|
}
|
|
|
|
if( _fileOut != stdout )
|
|
{
|
|
fclose( _fileOut );
|
|
}
|
|
|
|
if ( _pvExclusionBlock )
|
|
{
|
|
free( _pvExclusionBlock ) ;
|
|
}
|
|
|
|
if ( _apszExclusionArray )
|
|
{
|
|
free( _apszExclusionArray ) ;
|
|
}
|
|
|
|
} // Cleanup
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CopyHeaderToOutput
|
|
|
|
SYNOPSIS: Copies the specified header file to the output file.
|
|
|
|
ENTRY: fHeader - An open file stream (read access)
|
|
to the header file.
|
|
|
|
fOutput - An open file stream (write access)
|
|
to the output file.
|
|
|
|
NOTES: If any errors occur, FatalError() is called to terminate
|
|
the app.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
|
|
********************************************************************/
|
|
void CopyHeaderToOutput( FILE * fHeader,
|
|
FILE * fOutput )
|
|
{
|
|
char achBuffer[HEADER_COPY_BUFFER_SIZE];
|
|
size_t cbRead;
|
|
|
|
while( ( cbRead = fread( achBuffer,
|
|
sizeof(char),
|
|
HEADER_COPY_BUFFER_SIZE,
|
|
fHeader ) ) != 0 )
|
|
{
|
|
if( fwrite( achBuffer,
|
|
sizeof(char),
|
|
cbRead,
|
|
fOutput ) < cbRead )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ferror( fHeader ) || ferror( fOutput ) )
|
|
{
|
|
FatalError( 2, _szErrorCopyingHeader );
|
|
}
|
|
|
|
} // CopyHeaderToOutput
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ExtractSymbol
|
|
|
|
SYNOPSIS: Extracts a public symbol from a COFF output line.
|
|
|
|
ENTRY: pszLineFromCoff - A text line output from the
|
|
"COFF -DUMP -SYM" command.
|
|
|
|
Note: The text in the line
|
|
will be modified by the strtok()
|
|
function!
|
|
|
|
pszSymbol - Will receive the extracted symbol,
|
|
if one is found.
|
|
|
|
RETURNS: int - !0 if a symbol was extracted,
|
|
0 otherwise.
|
|
|
|
NOTES: Here's an example of the input (output from LINK32).
|
|
The symbol -$- indicates places where I broke the line
|
|
for clarity. This just one line:
|
|
|
|
009 00000000 SECT2 notype () External | -$-
|
|
??0APPLICATION@@IAE@PAUHINSTANCE__@@HIIII@Z -$-
|
|
(protected: __thiscall APPLICATION::APPLICATION( -$-
|
|
struct HINSTANCE__ *,int,unsigned int,unsigned int,-$-
|
|
unsigned int,unsigned int))
|
|
|
|
We choose only symbols which are part of a SECT and are
|
|
marked as "notype" and "External"
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
DavidHov 20-Oct-1993 update to new LINK32 output form.
|
|
|
|
********************************************************************/
|
|
int ExtractSymbol( char * pszLineFromCoff,
|
|
char * pszSymbol )
|
|
{
|
|
char * pszDelimiters = " \t\n";
|
|
char * pszSect = "SECT";
|
|
char * pszNoType = "notype";
|
|
char * pszExternal = "External";
|
|
char * pszToken;
|
|
char * pszPotentialSymbol;
|
|
char * pszScan;
|
|
|
|
//
|
|
// Verify that the first token is a hex number.
|
|
//
|
|
|
|
pszToken = strtok( pszLineFromCoff, pszDelimiters );
|
|
|
|
if( ( pszToken == NULL ) || !IsHexNumber( pszToken ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Verify that the second token is a hex number.
|
|
//
|
|
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( ( pszToken == NULL ) || !IsHexNumber( pszToken ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// The third token must be SECTn (where n is one
|
|
// or more hex digits).
|
|
//
|
|
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszToken == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( ( _strnicmp( pszToken, pszSect, 4 ) )
|
|
|| ! IsHexNumber( pszToken + 4 ) )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
//
|
|
// Next, we have to have "notype"
|
|
//
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszToken == NULL ||
|
|
_stricmp( pszToken, pszNoType ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Functions have a () next, data exports don't.
|
|
//
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszToken == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( strcmp( pszToken, "()" ) != 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Next, we need "External"
|
|
//
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszToken == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( pszToken == NULL ||
|
|
_stricmp( pszToken, pszExternal ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Now, the symbol introducer: "|"
|
|
//
|
|
pszToken = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszToken == NULL ||
|
|
_stricmp( pszToken, "|" ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Finally, the mangled (decorated) symbol itself.
|
|
//
|
|
|
|
pszPotentialSymbol = strtok( NULL, pszDelimiters );
|
|
|
|
if( pszPotentialSymbol == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Strip prefix from PowerPC function symbols
|
|
//
|
|
if( _fPowerPC )
|
|
{
|
|
pszPotentialSymbol += 2 ;
|
|
}
|
|
|
|
//
|
|
// Strip prefix from IA-64 function symbols
|
|
//
|
|
if( _fIA64 )
|
|
{
|
|
pszPotentialSymbol += 1 ;
|
|
}
|
|
|
|
if( strlen( pszPotentialSymbol ) > MAX_SYMBOL )
|
|
{
|
|
fprintf( stderr,
|
|
_szSymbolTooLong,
|
|
pszPotentialSymbol );
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Got one.
|
|
//
|
|
|
|
strcpy( pszSymbol, pszPotentialSymbol );
|
|
return 1;
|
|
|
|
} // ExtractSymbol
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: FatalError and NonFatalError
|
|
|
|
SYNOPSIS: Prints an error message to stderr, then terminates
|
|
the application.
|
|
|
|
ENTRY: err - An error code for the exit()
|
|
stdlib function.
|
|
|
|
pszFmt - A format string for vsprintf().
|
|
|
|
... - Any other arguments required
|
|
by the format string.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
|
|
********************************************************************/
|
|
|
|
void __cdecl NonFatalError (
|
|
char * pszFmt,
|
|
... )
|
|
{
|
|
char szBuffer[MAX_ERROR_MESSAGE+1];
|
|
va_list ArgPtr;
|
|
|
|
va_start( ArgPtr, pszFmt );
|
|
|
|
fprintf( stderr, "%s => ", _pszProgramName );
|
|
vsprintf( szBuffer, pszFmt, ArgPtr );
|
|
fprintf( stderr, "%s\n", szBuffer );
|
|
|
|
va_end( ArgPtr );
|
|
|
|
} // NonFatalError
|
|
|
|
void __cdecl FatalError( int err,
|
|
char * pszFmt,
|
|
... )
|
|
{
|
|
char szBuffer[MAX_ERROR_MESSAGE+1];
|
|
va_list ArgPtr;
|
|
|
|
va_start( ArgPtr, pszFmt );
|
|
|
|
fprintf( stderr, "%s => ", _pszProgramName );
|
|
vsprintf( szBuffer, pszFmt, ArgPtr );
|
|
fprintf( stderr, "%s\n", szBuffer );
|
|
|
|
va_end( ArgPtr );
|
|
|
|
Cleanup();
|
|
exit( err );
|
|
|
|
} // FatalError
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: IsHexNumber
|
|
|
|
SYNOPSIS: Determines if the specified string contains a hexadecimal
|
|
number.
|
|
|
|
ENTRY: pszHexNumber - The hex number.
|
|
|
|
EXIT: int - !0 if it *is* a hex number,
|
|
0 if it isn't.
|
|
|
|
HISTORY:
|
|
KeithMo 12-Aug-1992 Created.
|
|
|
|
********************************************************************/
|
|
int IsHexNumber( char * pszHexNumber )
|
|
{
|
|
int fResult = 1;
|
|
char ch;
|
|
|
|
while( ch = *pszHexNumber++ )
|
|
{
|
|
if( !isxdigit( ch ) )
|
|
{
|
|
fResult = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
|
|
} // IsHexNumber
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NoPath
|
|
|
|
SYNOPSIS: Extracts the filename portion of a path.
|
|
|
|
ENTRY: pszPathName - Contains a path name. The name
|
|
is not necessarily canonicalized,
|
|
and may contain just a filename
|
|
component.
|
|
|
|
EXIT: char * - The filename component.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
|
|
********************************************************************/
|
|
char * NoPath( char * pszPathName )
|
|
{
|
|
char * pszTmp;
|
|
char ch;
|
|
|
|
pszTmp = pszPathName;
|
|
|
|
while( ( ch = *pszPathName++ ) != '\0' )
|
|
{
|
|
if( ( ch == '\\' ) || ( ch == ':' ) )
|
|
{
|
|
pszTmp = pszPathName;
|
|
}
|
|
}
|
|
|
|
return pszTmp;
|
|
|
|
} // NoPath
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ProcessCommandLine
|
|
|
|
SYNOPSIS: Parse command line arguments, setting appropriate globals.
|
|
|
|
ENTRY: cArgs - Number of command line arguments.
|
|
|
|
pArgs - An array of pointers to the
|
|
command line arguments.
|
|
|
|
NOTES: See the Usage() function for valid command line arguments.
|
|
|
|
HISTORY:
|
|
KeithMo 12-Aug-1992 Broke out of main().
|
|
DaveWolfe 06-Jul-1994 Added -ppc.
|
|
|
|
********************************************************************/
|
|
void ProcessCommandLine( int cArgs,
|
|
char * pArgs[] )
|
|
{
|
|
int i;
|
|
char chSwitch;
|
|
|
|
//
|
|
// Setup our defaults.
|
|
//
|
|
|
|
_fileIn = stdin;
|
|
_fileOut = stdout;
|
|
_fileHeader = NULL;
|
|
|
|
_fStripLeadingUnderscore = 0;
|
|
_fNukeStdcallDecoration = 0;
|
|
_fPowerPC = 0;
|
|
_fIA64 = 0;
|
|
|
|
//
|
|
// Parse the command line arguments.
|
|
//
|
|
|
|
for( i = 1 ; i < cArgs ; i++ )
|
|
{
|
|
//
|
|
// Get the argument.
|
|
//
|
|
|
|
char * pszArg = pArgs[i];
|
|
char * pszParam;
|
|
|
|
//
|
|
// All of our valid arguments *must* start
|
|
// with a switch character. Enforce this.
|
|
//
|
|
|
|
if( ( *pszArg != '-' ) && ( *pszArg != '/' ) )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
chSwitch = *++pszArg;
|
|
|
|
//
|
|
// pszParam will either be NULL (for switches such
|
|
// as -s) or point to the text just past the colon
|
|
// (for switches such as -i:file).
|
|
//
|
|
|
|
if( ( pszArg[1] == ':' ) && ( pszArg[2] != '\0' ) )
|
|
{
|
|
pszParam = pszArg + 2;
|
|
}
|
|
else
|
|
{
|
|
pszParam = NULL;
|
|
}
|
|
|
|
//
|
|
// Check for valid arguments.
|
|
//
|
|
|
|
switch( chSwitch )
|
|
{
|
|
case 'p' :
|
|
case 'P' :
|
|
//
|
|
// -ppc
|
|
//
|
|
// Strip prefix ".." from "..symbol".
|
|
//
|
|
if( _stricmp( pszArg, "ppc") != 0 )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fPowerPC = 1;
|
|
break;
|
|
|
|
case 'h' :
|
|
case 'H' :
|
|
//
|
|
// -h:header_file
|
|
//
|
|
// If a header file has already been specified, or
|
|
// if there is no parameter after the switch, bag-out.
|
|
//
|
|
|
|
if( ( _fileHeader != NULL ) || ( pszParam == NULL ) )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fileHeader = fopen( pszParam, "r" );
|
|
|
|
if( _fileHeader == NULL )
|
|
{
|
|
FatalError( 1, _szCannotOpenForRead, pszParam );
|
|
}
|
|
break;
|
|
|
|
case 'i' :
|
|
case 'I' :
|
|
|
|
if (pszParam == NULL) {
|
|
//
|
|
// -ia64
|
|
//
|
|
// Strip prefix "." from ".symbol".
|
|
//
|
|
if( _stricmp( pszArg, "ia64") != 0 )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fIA64 = 1;
|
|
} else {
|
|
|
|
//
|
|
// -i:input_file
|
|
//
|
|
// If an input file has already been specified, or
|
|
// if there is no parameter after the switch, bag-out.
|
|
//
|
|
|
|
if( ( _fileIn != stdin ) || ( pszParam == NULL ) )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fileIn = fopen( pszParam, "r" );
|
|
|
|
if( _fileIn == NULL )
|
|
{
|
|
FatalError( 1, _szCannotOpenForRead, pszParam );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'o' :
|
|
case 'O' :
|
|
//
|
|
// -o:output_file
|
|
//
|
|
// If an output file has already been specified, or
|
|
// if there is no parameter after the switch, bag-out.
|
|
//
|
|
|
|
if( ( _fileOut != stdout ) || ( pszParam == NULL ) )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fileOut = fopen( pszParam, "w" );
|
|
|
|
if( _fileOut == NULL )
|
|
{
|
|
FatalError( 1, _szCannotOpenForWrite, pszParam );
|
|
}
|
|
break;
|
|
|
|
case 's' :
|
|
case 'S' :
|
|
//
|
|
// -s
|
|
//
|
|
// If this switch has already been specified, bag-out.
|
|
//
|
|
|
|
if( _fStripLeadingUnderscore )
|
|
{
|
|
Usage();
|
|
}
|
|
|
|
_fStripLeadingUnderscore = 1;
|
|
break;
|
|
|
|
case 'n' :
|
|
case 'N' :
|
|
_fNukeStdcallDecoration = 1 ;
|
|
break ;
|
|
|
|
case 'x' :
|
|
case 'X' :
|
|
_pszExclusionListFile = pszParam ;
|
|
break ;
|
|
|
|
case '?' :
|
|
//
|
|
// -?
|
|
//
|
|
// Give the poor user a clue.
|
|
//
|
|
|
|
Usage();
|
|
break;
|
|
|
|
default :
|
|
//
|
|
// Invalid switch.
|
|
//
|
|
// Tell the user the bad news, then bag-out.
|
|
//
|
|
|
|
fprintf( stderr, _szInvalidSwitch, chSwitch );
|
|
Usage();
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // ProcessCommandLine
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: StripStdcallDecoration
|
|
|
|
SYNOPSIS: Stdcall builds use a weak form of type-safe linkage.
|
|
This is implemented by appending "@nn" to the end
|
|
of each symbol, where "nn" is the number of *bytes*
|
|
passed as parameters.
|
|
|
|
COFF, on the other hand, does *not* want to see
|
|
this symbol decoration in .DEF files. So, we remove
|
|
it here.
|
|
|
|
ENTRY: pszSymbol - The symbol to munge.
|
|
|
|
NOTES: This routine is *NOT* DBCS safe! Do we care?
|
|
|
|
HISTORY:
|
|
KeithMo 14-Sep-1992 Created.
|
|
|
|
********************************************************************/
|
|
void StripStdcallDecoration( char * pszSymbol )
|
|
{
|
|
int count = 0 ;
|
|
|
|
//
|
|
// Find the last character.
|
|
//
|
|
|
|
pszSymbol += strlen( pszSymbol ) - 1;
|
|
|
|
//
|
|
// Skip any *decimal* numbers.
|
|
//
|
|
|
|
while( isdigit( *pszSymbol ) )
|
|
{
|
|
pszSymbol--;
|
|
count++ ;
|
|
}
|
|
|
|
//
|
|
// If we're now pointing at a "@", terminate the string here.
|
|
//
|
|
|
|
if( count && *pszSymbol == '@' )
|
|
{
|
|
*pszSymbol = '\0';
|
|
}
|
|
|
|
} // StripStdcallDecoration
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: Usage
|
|
|
|
SYNOPSIS: Displays usage information if the user gives us a
|
|
bogus command line.
|
|
|
|
HISTORY:
|
|
KeithMo 09-Aug-1992 Created.
|
|
|
|
DaveWolfe 06-Jul-1994 Added -ppc option.
|
|
|
|
********************************************************************/
|
|
void Usage( void )
|
|
{
|
|
fprintf( stderr, "use: %s [options]\n", _pszProgramName );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, "Valid options are:\n" );
|
|
fprintf( stderr, " -i:input_file = source file\n" );
|
|
fprintf( stderr, " -o:output_file = destination file\n" );
|
|
fprintf( stderr, " -h:header_file = header to prepend before symbols\n" );
|
|
fprintf( stderr, " -s = strip first leading underscore from symbols\n" );
|
|
fprintf( stderr, " -n = do not strip __stdcall decoration @nn\n" );
|
|
fprintf( stderr, " -x:excl_file = name of file containing excluded symbols\n" );
|
|
fprintf( stderr, " -ppc = input is PowerPC symbol dump\n" );
|
|
fprintf( stderr, " -ia64 = input is IA-64 symbol dump\n" );
|
|
fprintf( stderr, " -? = show this help\n" );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, "Defaults are:\n" );
|
|
fprintf( stderr, " input_file = stdin\n" );
|
|
fprintf( stderr, " output_file = stdout\n" );
|
|
fprintf( stderr, " header_file = none\n" );
|
|
fprintf( stderr, " don't strip first leading underscore from symbol\n" );
|
|
fprintf( stderr, " input is not PowerPC symbol dump\n" );
|
|
|
|
Cleanup();
|
|
exit( 1 );
|
|
|
|
} // Usage
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CreateExclusionList
|
|
|
|
SYNOPSIS: Reads a text file of excluded export names into memory,
|
|
sorts it and builds a lookup table compatible with
|
|
bsearch().
|
|
|
|
Returns -1 if failure or the count of the number
|
|
of items in the created array.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
int __cdecl qsortStrings ( const void * pa, const void * pb )
|
|
{
|
|
return strcmp( *((const char * *) pa), *((const char * *) pb) ) ;
|
|
}
|
|
|
|
int CreateExclusionList ( char * pszFileName,
|
|
void * * pvData,
|
|
char * * * apszStrings )
|
|
{
|
|
int cItems, i ;
|
|
int result = -1 ;
|
|
long cbFileSize, cbBlockSize ;
|
|
char * pszData = NULL,
|
|
* psz,
|
|
* pszNext ;
|
|
|
|
char * * ppszArray = NULL ;
|
|
|
|
char chRec [ MAX_LINE_FROM_COFF ] ;
|
|
|
|
FILE * pf = NULL ;
|
|
|
|
do
|
|
{
|
|
pf = fopen( pszFileName, "r" ) ;
|
|
|
|
if ( pf == NULL )
|
|
break;
|
|
|
|
if (fseek( pf, 0, SEEK_END ) == -1)
|
|
break;
|
|
cbFileSize = ftell( pf ) ;
|
|
if (fseek( pf, 0, SEEK_SET ) == -1)
|
|
break;
|
|
|
|
cbBlockSize = cbFileSize + (cbFileSize / 2) ;
|
|
|
|
pszData = (char *) malloc( cbBlockSize ) ;
|
|
|
|
if ( pszData == NULL )
|
|
break ;
|
|
|
|
for ( cItems = 0, pszNext = pszData ;
|
|
(!feof( pf )) && (psz = fgets( chRec, sizeof chRec, pf )) ; )
|
|
{
|
|
int lgt ;
|
|
char * pszEnd ;
|
|
|
|
while ( *psz <= ' ' && *psz != 0 )
|
|
{
|
|
psz++ ;
|
|
}
|
|
|
|
if ( (lgt = strlen( psz )) == 0 )
|
|
continue ;
|
|
|
|
pszEnd = psz + lgt ;
|
|
|
|
do
|
|
{
|
|
--pszEnd ;
|
|
} while ( pszEnd > psz && *pszEnd <= ' ' ) ;
|
|
|
|
lgt = (int)(++pszEnd - psz) ;
|
|
*pszEnd = 0 ;
|
|
|
|
if ( pszNext + lgt - pszData >= cbBlockSize )
|
|
{
|
|
cItems = -1 ;
|
|
break ;
|
|
}
|
|
|
|
strcpy( pszNext, psz ) ;
|
|
pszNext += lgt+1 ;
|
|
cItems++ ;
|
|
}
|
|
|
|
*pszNext = 0 ;
|
|
|
|
if ( cItems <= 0 )
|
|
{
|
|
if ( cItems == 0 )
|
|
result = 0 ;
|
|
break ;
|
|
}
|
|
|
|
ppszArray = (char * *) malloc( cItems * sizeof (char *) ) ;
|
|
if ( ppszArray == NULL )
|
|
break ;
|
|
|
|
for ( i = 0, pszNext = pszData ;
|
|
*pszNext ;
|
|
pszNext += strlen( pszNext ) + 1 )
|
|
{
|
|
ppszArray[i++] = pszNext ;
|
|
}
|
|
|
|
qsort( (void *) ppszArray,
|
|
cItems,
|
|
sizeof (char *),
|
|
& qsortStrings ) ;
|
|
|
|
result = cItems ;
|
|
|
|
} while ( 0 ) ;
|
|
|
|
if ( pf != NULL )
|
|
{
|
|
fclose( pf ) ;
|
|
}
|
|
|
|
if ( result <= 0 )
|
|
{
|
|
if ( pszData )
|
|
{
|
|
free( pszData ) ;
|
|
pszData = NULL ;
|
|
}
|
|
if ( ppszArray )
|
|
{
|
|
free( ppszArray ) ;
|
|
ppszArray = NULL ;
|
|
}
|
|
}
|
|
|
|
*pvData = (void *) pszData ;
|
|
*apszStrings = ppszArray ;
|
|
|
|
return result ;
|
|
}
|
|
|
|
int ExcludedSymbol ( char * pszSymbol )
|
|
{
|
|
if ( _apszExclusionArray == NULL )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
return bsearch( (void *) & pszSymbol,
|
|
(void *) _apszExclusionArray,
|
|
_cExclusionItems,
|
|
sizeof (char *),
|
|
& qsortStrings ) != NULL ;
|
|
}
|
|
|
|
int ValidSymbol ( const char * psz )
|
|
{
|
|
int i = 0 ;
|
|
|
|
for ( ; apszIgnore[i] ; i++ )
|
|
{
|
|
if ( _strnicmp( apszIgnore[i],
|
|
psz,
|
|
strlen( apszIgnore[i] ) ) == 0 )
|
|
return 0 ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
// End of UIXPORT.C
|