2002-10-04 06:40:43 +04:00
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
2004-04-26 01:07:34 +04:00
* * * * * * BEGIN LICENSE BLOCK * * * * *
* Version : MPL 1.1 / GPL 2.0 / LGPL 2.1
2002-10-04 06:40:43 +04:00
*
2004-04-26 01:07:34 +04:00
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
2002-10-04 06:40:43 +04:00
*
* The Original Code is msmap2tsv . c code , released
* Oct 3 , 2002.
*
2004-04-26 01:07:34 +04:00
* The Initial Developer of the Original Code is
* Netscape Communications Corporation .
* Portions created by the Initial Developer are Copyright ( C ) 2002
* the Initial Developer . All Rights Reserved .
2002-10-04 06:40:43 +04:00
*
* Contributor ( s ) :
2004-04-26 01:07:34 +04:00
* Garrett Arch Blythe , 03 - October - 2002
*
* Alternatively , the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later ( the " GPL " ) , or
* the GNU Lesser General Public License Version 2.1 or later ( the " LGPL " ) ,
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above . If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL , and not to allow others to
* use your version of this file under the terms of the MPL , indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL . If you do not delete
* the provisions above , a recipient may use your version of this file under
* the terms of any one of the MPL , the GPL or the LGPL .
*
* * * * * * END LICENSE BLOCK * * * * * */
2002-10-04 06:40:43 +04:00
2002-10-04 06:33:15 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <ctype.h>
# include "msmap.h"
2002-12-15 01:53:31 +03:00
# if defined(_WIN32)
# include <windows.h>
# include <imagehlp.h>
# define F_DEMANGLE 1
2003-01-09 11:03:23 +03:00
# define DEMANGLE_STATE_NORMAL 0
# define DEMANGLE_STATE_QDECODE 1
# define DEMANGLE_STATE_PROLOGUE_1 2
# define DEMANGLE_STATE_HAVE_TYPE 3
# define DEMANGLE_STATE_DEC_LENGTH 4
# define DEMANGLE_STATE_HEX_LENGTH 5
# define DEMANGLE_STATE_PROLOGUE_SECONDARY 6
# define DEMANGLE_STATE_DOLLAR_1 7
# define DEMANGLE_STATE_DOLLAR_2 8
# define DEMANGLE_STATE_START 9
# define DEMANGLE_STATE_STOP 10
2003-01-24 03:27:17 +03:00
# define DEMANGLE_SAFE_CHAR(eval) (isprint(eval) ? eval : ' ')
2003-01-09 11:03:23 +03:00
2002-12-15 01:53:31 +03:00
# else
# define F_DEMANGLE 0
# endif /* WIN32 */
2002-10-04 06:33:15 +04:00
# define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
# define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
2003-01-22 17:06:15 +03:00
typedef struct __struct_SymDB_Size
/*
* * The size of the symbol .
* * The size is nested withing a symbols structures to produce a fast
* * lookup path .
* * The objects are listed in case the client of the symdb needs to
* * match the object name in the scenario where multiple symbol
* * sizes are present .
* *
* * mSize The size of the symbol in these objects .
* * mObjects A list of objects containing said symbol .
* * mObjectCount Number of objects .
*/
{
unsigned mSize ;
char * * mObjects ;
unsigned mObjectCount ;
}
SymDB_Size ;
typedef struct __struct_SymDB_Section
/*
* * Each section for a symbol has a list of sizes .
* * Should there be exactly one size for the symbol , then that
* * is the size that should be accepted .
* * If there is more than one size , then a match on the object
* * should be attempted , held withing each size .
* *
* * mName The section name .
* * mSizes The varoius sizes of the symbol in this section .
* * mSizeCount The number of available sizes .
*/
{
char * mName ;
SymDB_Size * mSizes ;
unsigned mSizeCount ;
}
SymDB_Section ;
typedef struct __struct_SymDB_Symbol
/*
* * Each symbol has at least one section .
* * The section indicates what type of symbol a client may be looking for .
* * If there is no match on the section , then the client should not trust
* * the symbdb .
* *
* * mName The mangled name of the symbol .
* * mSections Various sections this symbol belongs to .
* * mSectionCount The number of sections .
*/
{
char * mName ;
SymDB_Section * mSections ;
unsigned mSectionCount ;
}
SymDB_Symbol ;
2003-01-23 18:13:24 +03:00
# define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */
2003-01-22 17:06:15 +03:00
typedef struct __struct_SymDB_Container
/*
* * The symbol DB container object .
* * The goal of the symbol DB is to have exactly one SymDB_Symbol for each
* * mangled name , no matter how ever many identical mangled names there
* * are in the input .
* * The input is already expected to be well sorted , futher this leads to
* * the ability to binary search for symbol name matches .
* *
* * mSymbols The symbols .
* * mSymbolCount The number of symbols in the DB .
2003-01-23 18:13:24 +03:00
* * mSymbolCapacity The number of symbols we can hold ( before realloc ) .
2003-01-22 17:06:15 +03:00
*/
{
SymDB_Symbol * mSymbols ;
unsigned mSymbolCount ;
2003-01-23 18:13:24 +03:00
unsigned mSymbolCapacity ;
2003-01-22 17:06:15 +03:00
}
SymDB_Container ;
2002-10-04 06:33:15 +04:00
typedef struct __struct_Options
/*
* * Options to control how we perform .
* *
2002-11-16 01:48:39 +03:00
* * mProgramName Used in help text .
* * mInput File to read for input .
* * Default is stdin .
* * mInputName Name of the file .
* * mOutput Output file , append .
* * Default is stdout .
* * mOutputName Name of the file .
* * mHelp Wether or not help should be shown .
* * mMatchModules Array of strings which the module name should match .
* * mMatchModuleCount Number of items in array .
2003-01-22 17:06:15 +03:00
* * mSymDBName Symbol DB filename .
2003-01-23 18:13:24 +03:00
* * mBatchMode Batch mode .
* * When in batch mode , the input file contains a list of
* * map files to process .
* * Normally the input file is a single map file itself .
2002-10-04 06:33:15 +04:00
*/
{
const char * mProgramName ;
FILE * mInput ;
char * mInputName ;
FILE * mOutput ;
char * mOutputName ;
int mHelp ;
2002-11-16 01:48:39 +03:00
char * * mMatchModules ;
unsigned mMatchModuleCount ;
2003-01-22 17:06:15 +03:00
char * mSymDBName ;
SymDB_Container * mSymDB ;
2003-01-23 18:13:24 +03:00
int mBatchMode ;
2002-10-04 06:33:15 +04:00
}
Options ;
typedef struct __struct_Switch
/*
* * Command line options .
*/
{
const char * mLongName ;
const char * mShortName ;
int mHasValue ;
const char * mValue ;
const char * mDescription ;
}
Switch ;
# define DESC_NEWLINE "\n\t\t"
static Switch gInputSwitch = { " --input " , " -i " , 1 , NULL , " Specify input file. " DESC_NEWLINE " stdin is default. " } ;
static Switch gOutputSwitch = { " --output " , " -o " , 1 , NULL , " Specify output file. " DESC_NEWLINE " Appends if file exists. " DESC_NEWLINE " stdout is default. " } ;
static Switch gHelpSwitch = { " --help " , " -h " , 0 , NULL , " Information on usage. " } ;
2002-11-16 01:48:39 +03:00
static Switch gMatchModuleSwitch = { " --match-module " , " -mm " , 1 , NULL , " Specify a valid module name. " DESC_NEWLINE " Multiple specifications allowed. " DESC_NEWLINE " If a module name does not match one of the names specified then no output will occur. " } ;
2003-01-22 17:06:15 +03:00
static Switch gSymDBSwitch = { " --symdb " , " -sdb " , 1 , NULL , " Specify a symbol tsv db input file. " DESC_NEWLINE " Such a symdb is produced using the tool msdump2symdb. " DESC_NEWLINE " This allows better symbol size approximations. " DESC_NEWLINE " The symdb file must be pre-sorted. " } ;
2003-01-23 18:13:24 +03:00
static Switch gBatchModeSwitch = { " --batch " , " -b " , 0 , NULL , " Runs in batch mode. " DESC_NEWLINE " The input file contains a list of map files. " DESC_NEWLINE " Normally the input file is a map file itself. " DESC_NEWLINE " This eliminates reprocessing the symdb for multiple map files. " } ;
2002-10-04 06:33:15 +04:00
static Switch * gSwitches [ ] = {
& gInputSwitch ,
& gOutputSwitch ,
2002-11-16 01:48:39 +03:00
& gMatchModuleSwitch ,
2003-01-22 17:06:15 +03:00
& gSymDBSwitch ,
2003-01-23 18:13:24 +03:00
& gBatchModeSwitch ,
2002-10-04 06:33:15 +04:00
& gHelpSwitch
} ;
typedef struct __struct_MSMap_ReadState
/*
* * Keep track of what state we are while reading input .
* * This gives the input context in which we absorb the datum .
*/
{
int mHasModule ;
int mHasTimestamp ;
int mHasPreferredLoadAddress ;
int mHasSegmentData ;
int mSegmentDataSkippedLine ;
int mHasPublicSymbolData ;
int mHasPublicSymbolDataSkippedLines ;
int mHasEntryPoint ;
int mFoundStaticSymbols ;
}
MSMap_ReadState ;
char * skipWhite ( char * inScan )
/*
* * Skip whitespace .
*/
{
char * retval = inScan ;
while ( isspace ( * retval ) )
{
retval + + ;
}
return retval ;
}
void trimWhite ( char * inString )
/*
* * Remove any whitespace from the end of the string .
*/
{
int len = strlen ( inString ) ;
while ( len )
{
len - - ;
if ( isspace ( * ( inString + len ) ) )
{
* ( inString + len ) = ' \0 ' ;
}
else
{
break ;
}
}
}
char * lastWord ( char * inString )
/*
* * Finds and returns the last word in a string .
* * It is assumed no whitespace is at the end of the string .
*/
{
int mod = 0 ;
int len = strlen ( inString ) ;
while ( len )
{
len - - ;
if ( isspace ( * ( inString + len ) ) )
{
mod = 1 ;
break ;
}
}
return inString + len + mod ;
}
2003-01-23 18:13:24 +03:00
MSMap_Segment * getSymbolSection ( MSMap_Module * inModule , MSMap_Symbol * inoutSymbol )
/*
* * Perform a lookup for the section of the symbol .
* * The function could cache the value .
*/
{
MSMap_Segment * retval = NULL ;
if ( NULL ! = inoutSymbol - > mSection )
{
/*
* * Use cached value .
*/
retval = inoutSymbol - > mSection ;
}
else
{
unsigned secLoop = 0 ;
/*
* * Go through sections in module to find the match for the symbol .
*/
for ( secLoop = 0 ; secLoop < inModule - > mSegmentCount ; secLoop + + )
{
if ( inoutSymbol - > mPrefix = = inModule - > mSegments [ secLoop ] . mPrefix )
{
if ( inoutSymbol - > mOffset > = inModule - > mSegments [ secLoop ] . mOffset )
{
if ( inoutSymbol - > mOffset < ( inModule - > mSegments [ secLoop ] . mOffset + inModule - > mSegments [ secLoop ] . mLength ) )
{
/*
* * We have the section .
*/
retval = & inModule - > mSegments [ secLoop ] ;
2003-01-23 21:59:25 +03:00
break ;
2003-01-23 18:13:24 +03:00
}
}
}
}
/*
* * Cache the value for next time .
*/
inoutSymbol - > mSection = retval ;
}
return retval ;
}
2003-01-22 17:06:15 +03:00
int readSymDB ( const char * inDBName , SymDB_Container * * outDB )
/*
* * Intialize the symbol DB .
* * Only call if the symbol DB should be initialized .
*/
{
int retval = 0 ;
/*
* * Initialize out arguments .
*/
if ( NULL ! = outDB )
{
* outDB = NULL ;
}
if ( NULL ! = outDB & & NULL ! = inDBName )
{
2003-01-23 18:13:24 +03:00
FILE * symDB = NULL ;
symDB = fopen ( inDBName , " r " ) ;
if ( NULL ! = symDB )
{
* outDB = ( SymDB_Container * ) calloc ( 1 , sizeof ( SymDB_Container ) ) ;
if ( NULL ! = * outDB )
{
char lineBuf [ 0x400 ] ;
char * symbol = NULL ;
char * section = NULL ;
char * object = NULL ;
char * length = NULL ;
unsigned lengthNum = 0 ;
char * endLength = NULL ;
/*
* * Read the file line by line .
*/
while ( 0 = = retval & & NULL ! = fgets ( lineBuf , sizeof ( lineBuf ) , symDB ) )
{
trimWhite ( lineBuf ) ;
/*
* * Each line has four arguments . tab seperated values ( tsv ) .
* * Symbol
* * Section
* * Length
* * Object
*/
symbol = skipWhite ( lineBuf ) ;
if ( NULL = = symbol )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " File does not appear to be a symbol DB. " ) ;
break ;
}
section = strchr ( symbol , ' \t ' ) ;
if ( NULL = = section )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " File does not appear to be a symbol DB. " ) ;
break ;
}
* section = ' \0 ' ;
section + + ;
length = strchr ( section , ' \t ' ) ;
if ( NULL = = length )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " File does not appear to be a symbol DB. " ) ;
break ;
}
* length = ' \0 ' ;
length + + ;
object = strchr ( length , ' \t ' ) ;
if ( NULL = = object )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " File does not appear to be a symbol DB. " ) ;
break ;
}
* object = ' \0 ' ;
object + + ;
/*
* * Convert the length into a number .
*/
errno = 0 ;
lengthNum = strtoul ( length , & endLength , 16 ) ;
if ( 0 = = errno & & endLength ! = length )
{
SymDB_Symbol * dbSymbol = NULL ;
SymDB_Section * dbSection = NULL ;
SymDB_Size * dbSize = NULL ;
char * dbObject = NULL ;
void * moved = NULL ;
/*
* * Are we looking at the same symbol as last line ?
* * This assumes the symdb is pre sorted ! ! !
*/
if ( 0 ! = ( * outDB ) - > mSymbolCount )
{
unsigned index = ( * outDB ) - > mSymbolCount - 1 ;
if ( 0 = = strcmp ( ( * outDB ) - > mSymbols [ index ] . mName , symbol ) )
{
dbSymbol = & ( * outDB ) - > mSymbols [ index ] ;
}
}
/*
* * May need to create symbol .
*/
if ( NULL = = dbSymbol )
{
/*
* * Could be time to grow the symbol pool .
*/
if ( ( * outDB ) - > mSymbolCount > = ( * outDB ) - > mSymbolCapacity )
{
moved = realloc ( ( * outDB ) - > mSymbols , sizeof ( SymDB_Symbol ) * ( ( * outDB ) - > mSymbolCapacity + SYMDB_SYMBOL_GROWBY ) ) ;
if ( NULL ! = moved )
{
( * outDB ) - > mSymbols = ( SymDB_Symbol * ) moved ;
memset ( & ( * outDB ) - > mSymbols [ ( * outDB ) - > mSymbolCapacity ] , 0 , sizeof ( SymDB_Symbol ) * SYMDB_SYMBOL_GROWBY ) ;
( * outDB ) - > mSymbolCapacity + = SYMDB_SYMBOL_GROWBY ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " Unable to grow symbol DB symbol array. " ) ;
break ;
}
}
if ( ( * outDB ) - > mSymbolCount < ( * outDB ) - > mSymbolCapacity )
{
dbSymbol = & ( * outDB ) - > mSymbols [ ( * outDB ) - > mSymbolCount ] ;
( * outDB ) - > mSymbolCount + + ;
dbSymbol - > mName = strdup ( symbol ) ;
if ( NULL = = dbSymbol - > mName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , symbol , " Unable to duplicate string. " ) ;
break ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , symbol , " Unable to grow symbol DB for symbol. " ) ;
break ;
}
}
/*
* * Assume we have the symbol .
* *
* * Is this the same section as the last section in the symbol ?
* * This assumes the symdb was presorted ! ! ! !
*/
if ( 0 ! = dbSymbol - > mSectionCount )
{
unsigned index = dbSymbol - > mSectionCount - 1 ;
if ( 0 = = strcmp ( dbSymbol - > mSections [ index ] . mName , section ) )
{
dbSection = & dbSymbol - > mSections [ index ] ;
}
}
/*
* * May need to create the section .
*/
if ( NULL = = dbSection )
{
moved = realloc ( dbSymbol - > mSections , sizeof ( SymDB_Section ) * ( dbSymbol - > mSectionCount + 1 ) ) ;
if ( NULL ! = moved )
{
dbSymbol - > mSections = ( SymDB_Section * ) moved ;
dbSection = & dbSymbol - > mSections [ dbSymbol - > mSectionCount ] ;
dbSymbol - > mSectionCount + + ;
memset ( dbSection , 0 , sizeof ( SymDB_Section ) ) ;
dbSection - > mName = strdup ( section ) ;
if ( NULL = = dbSection - > mName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , section , " Unable to duplicate string. " ) ;
break ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , section , " Unable to grow symbol sections for symbol DB. " ) ;
break ;
}
}
/*
* * Assume we have the section .
* *
* * Is this the same size as the last size ?
* * This assumes the symdb was presorted ! ! !
*/
if ( 0 ! = dbSection - > mSizeCount )
{
unsigned index = dbSection - > mSizeCount - 1 ;
if ( dbSection - > mSizes [ index ] . mSize = = lengthNum )
{
dbSize = & dbSection - > mSizes [ index ] ;
}
}
/*
* * May need to create the size in question .
*/
if ( NULL = = dbSize )
{
moved = realloc ( dbSection - > mSizes , sizeof ( SymDB_Size ) * ( dbSection - > mSizeCount + 1 ) ) ;
if ( NULL ! = moved )
{
dbSection - > mSizes = ( SymDB_Size * ) moved ;
dbSize = & dbSection - > mSizes [ dbSection - > mSizeCount ] ;
dbSection - > mSizeCount + + ;
memset ( dbSize , 0 , sizeof ( SymDB_Size ) ) ;
dbSize - > mSize = lengthNum ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , length , " Unable to grow symbol section sizes for symbol DB. " ) ;
break ;
}
}
/*
* * Assume we have the size .
* *
* * We assume a one to one correllation between size and object .
* * Always try to add the new object name .
* * As the symdb is assumed to be sorted , the object names should also be in order .
*/
moved = realloc ( dbSize - > mObjects , sizeof ( char * ) * ( dbSize - > mObjectCount + 1 ) ) ;
if ( NULL ! = moved )
{
dbObject = strdup ( object ) ;
dbSize - > mObjects = ( char * * ) moved ;
dbSize - > mObjects [ dbSize - > mObjectCount ] = dbObject ;
dbSize - > mObjectCount + + ;
if ( NULL = = dbObject )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , object , " Unable to duplicate string. " ) ;
break ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , object , " Unable to grow symbol section size objects for symbol DB. " ) ;
break ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , length , " Unable to convert symbol DB length into a number. " ) ;
break ;
}
}
if ( 0 = = retval & & 0 ! = ferror ( symDB ) )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " Unable to read file. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " Unable to allocate symbol DB. " ) ;
}
fclose ( symDB ) ;
symDB = NULL ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inDBName , " Unable to open symbol DB. " ) ;
}
2003-01-22 17:06:15 +03:00
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , " (NULL) " , " Invalid arguments. " ) ;
}
return retval ;
}
2003-01-23 18:13:24 +03:00
void cleanSymDB ( SymDB_Container * * inDB )
/*
* * Free it all up .
*/
{
if ( NULL ! = inDB & & NULL ! = * inDB )
{
unsigned symLoop = 0 ;
unsigned secLoop = 0 ;
unsigned sizLoop = 0 ;
unsigned objLoop = 0 ;
for ( symLoop = 0 ; symLoop < ( * inDB ) - > mSymbolCount ; symLoop + + )
{
for ( secLoop = 0 ; secLoop < ( * inDB ) - > mSymbols [ symLoop ] . mSectionCount ; secLoop + + )
{
for ( sizLoop = 0 ; sizLoop < ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mSizeCount ; sizLoop + + )
{
for ( objLoop = 0 ; objLoop < ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mSizes [ sizLoop ] . mObjectCount ; objLoop + + )
{
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mSizes [ sizLoop ] . mObjects [ objLoop ] ) ;
}
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mSizes [ sizLoop ] . mObjects ) ;
}
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mName ) ;
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mSections [ secLoop ] . mSizes ) ;
}
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mName ) ;
CLEANUP ( ( * inDB ) - > mSymbols [ symLoop ] . mSections ) ;
}
CLEANUP ( ( * inDB ) - > mSymbols ) ;
CLEANUP ( * inDB ) ;
}
}
int symDBLookup ( const void * inKey , const void * inItem )
/*
* * bsearch utility routine to find the symbol in the symdb .
*/
{
int retval = 0 ;
const char * key = ( const char * ) inKey ;
const SymDB_Symbol * symbol = ( const SymDB_Symbol * ) inItem ;
retval = strcmp ( key , symbol - > mName ) ;
return retval ;
}
int fillSymbolSizeFromDB ( Options * inOptions , MSMap_Module * inModule , MSMap_Symbol * inoutSymbol , const char * inMangledName )
2003-01-22 17:06:15 +03:00
/*
* * If we have a symbol DB , attempt to determine the real size of the symbol
* * up front .
* * This helps us later in the game to avoid performing size guesses by
* * offset .
*/
{
int retval = 0 ;
/*
* * May need to initialize symdb .
*/
if ( NULL = = inOptions - > mSymDB & & NULL ! = inOptions - > mSymDBName )
{
retval = readSymDB ( inOptions - > mSymDBName , & inOptions - > mSymDB ) ;
}
/*
* * Optional
*/
if ( 0 = = retval & & NULL ! = inOptions - > mSymDB )
{
2003-01-23 18:13:24 +03:00
void * match = NULL ;
2003-01-22 17:06:15 +03:00
/*
2003-01-23 18:13:24 +03:00
* * Find the symbol .
2003-01-22 17:06:15 +03:00
*/
2003-01-23 18:13:24 +03:00
match = bsearch ( inMangledName , inOptions - > mSymDB - > mSymbols , inOptions - > mSymDB - > mSymbolCount , sizeof ( SymDB_Symbol ) , symDBLookup ) ;
if ( NULL ! = match )
{
SymDB_Symbol * symbol = ( SymDB_Symbol * ) match ;
unsigned symDBSize = 0 ;
MSMap_Segment * mapSection = NULL ;
/*
* * We found the symbol .
* *
* * See if it has the section in question .
*/
mapSection = getSymbolSection ( inModule , inoutSymbol ) ;
if ( NULL ! = mapSection )
{
unsigned secLoop = 0 ;
for ( secLoop = 0 ; secLoop < symbol - > mSectionCount ; secLoop + + )
{
if ( 0 = = strcmp ( mapSection - > mSegment , symbol - > mSections [ secLoop ] . mName ) )
{
SymDB_Section * section = & symbol - > mSections [ secLoop ] ;
/*
* * We have a section match .
* * Should there be a single size for the symbol ,
* * then we just default to that .
* * If more than one size , we have to do an
* * object match search .
* * Should there be no object match , we do nothign .
*/
if ( 1 = = section - > mSizeCount )
{
symDBSize = section - > mSizes [ 0 ] . mSize ;
}
else
{
char * mapObject = NULL ;
/*
* * Figure out the map object file name .
* * Skip any colon .
* * If it doesn ' t have a . obj in it , not worth continuing .
*/
mapObject = strrchr ( inoutSymbol - > mObject , ' : ' ) ;
if ( NULL = = mapObject )
{
mapObject = inoutSymbol - > mObject ;
}
else
{
mapObject + + ; /* colon */
}
if ( NULL ! = strstr ( mapObject , " .obj " ) )
{
unsigned sizLoop = 0 ;
unsigned objLoop = 0 ;
SymDB_Size * size = NULL ;
for ( sizLoop = 0 ; sizLoop < section - > mSizeCount ; sizLoop + + )
{
size = & section - > mSizes [ sizLoop ] ;
for ( objLoop = 0 ; objLoop < size - > mObjectCount ; objLoop + + )
{
if ( NULL ! = strstr ( size - > mObjects [ objLoop ] , mapObject ) )
{
/*
* * As we matched the object , in a particular section ,
* * we ' ll go with this as the number .
*/
symDBSize = size - > mSize ;
break ;
}
}
/*
* * If the object loop broke early , we break too .
*/
if ( objLoop < size - > mObjectCount )
{
break ;
}
}
}
}
break ;
}
}
}
/*
* * Put the size in .
*/
inoutSymbol - > mSymDBSize = symDBSize ;
}
2003-01-22 17:06:15 +03:00
}
return retval ;
}
2002-12-15 01:53:31 +03:00
char * symdup ( const char * inSymbol )
/*
* * Attempts to demangle the symbol if appropriate .
* * Otherwise acts like strdup .
*/
{
char * retval = NULL ;
# if F_DEMANGLE
{
int isImport = 0 ;
if ( 0 = = strncmp ( " __imp_ " , inSymbol , 6 ) )
{
isImport = __LINE__ ;
inSymbol + = 6 ;
}
if ( ' ? ' = = inSymbol [ 0 ] )
{
char demangleBuf [ 0x200 ] ;
DWORD demangleRes = 0 ;
demangleRes = UnDecorateSymbolName ( inSymbol , demangleBuf , sizeof ( demangleBuf ) , UNDNAME_COMPLETE ) ;
if ( 0 ! = demangleRes )
{
2003-01-09 11:03:23 +03:00
if ( strcmp ( demangleBuf , " `string' " ) = = 0 )
{
/* attempt manual demangling of string prefix.. */
/* first make sure we have enough space for the
updated string - the demangled string will
always be shorter than strlen ( inSymbol ) and the
prologue will always be longer than the
" string: " that we tack on the front of the string
*/
char * curresult = retval = malloc ( strlen ( inSymbol ) + 11 ) ;
const char * curchar = inSymbol ;
int state = DEMANGLE_STATE_START ;
/* the hex state is for stuff like ?$EA which
really means hex value 0x40 */
char hex_state = 0 ;
char string_is_unicode = 0 ;
/* sometimes we get a null-termination before the
final @ sign - in that case , remember that
we ' ve seen the whole string */
int have_null_char = 0 ;
/* stick our user-readable prefix on */
strcpy ( curresult , " string: \" " ) ;
curresult + = 9 ;
while ( * curchar ) {
// process current state
switch ( state ) {
/* the Prologue states are divided up so
that someday we can try to decode
the random letters in between the ' @ '
signs . Also , some strings only have 2
prologue ' @ ' signs , so we have to
figure out how to distinguish between
them at some point . */
case DEMANGLE_STATE_START :
if ( * curchar = = ' @ ' )
state = DEMANGLE_STATE_PROLOGUE_1 ;
/* ignore all other states */
break ;
case DEMANGLE_STATE_PROLOGUE_1 :
switch ( * curchar ) {
case ' 0 ' :
string_is_unicode = 0 ;
state = DEMANGLE_STATE_HAVE_TYPE ;
break ;
case ' 1 ' :
string_is_unicode = 1 ;
state = DEMANGLE_STATE_HAVE_TYPE ;
break ;
/* ignore all other characters */
}
break ;
case DEMANGLE_STATE_HAVE_TYPE :
if ( * curchar > = ' 0 ' & & * curchar < = ' 9 ' ) {
state = DEMANGLE_STATE_DEC_LENGTH ;
} else if ( * curchar > = ' A ' & & * curchar < = ' Z ' ) {
state = DEMANGLE_STATE_HEX_LENGTH ;
}
case DEMANGLE_STATE_DEC_LENGTH :
/* decimal lengths don't have the 2nd
field
*/
if ( * curchar = = ' @ ' )
state = DEMANGLE_STATE_NORMAL ;
break ;
case DEMANGLE_STATE_HEX_LENGTH :
/* hex lengths have a 2nd field
( though I have no idea what it is for )
*/
if ( * curchar = = ' @ ' )
state = DEMANGLE_STATE_PROLOGUE_SECONDARY ;
break ;
case DEMANGLE_STATE_PROLOGUE_SECONDARY :
if ( * curchar = = ' @ ' )
state = DEMANGLE_STATE_NORMAL ;
break ;
case DEMANGLE_STATE_NORMAL :
switch ( * curchar ) {
case ' ? ' :
state = DEMANGLE_STATE_QDECODE ;
break ;
case ' @ ' :
state = DEMANGLE_STATE_STOP ;
break ;
default :
2003-01-24 03:27:17 +03:00
* curresult + + = DEMANGLE_SAFE_CHAR ( * curchar ) ;
2003-01-09 11:03:23 +03:00
state = DEMANGLE_STATE_NORMAL ;
break ;
}
break ;
/* found a '?' */
case DEMANGLE_STATE_QDECODE :
state = DEMANGLE_STATE_NORMAL ;
/* there are certain shortcuts, like
" ?3 " means " : "
*/
switch ( * curchar ) {
case ' 1 ' :
* curresult + + = ' / ' ;
break ;
case ' 2 ' :
* curresult + + = ' \\ ' ;
break ;
case ' 3 ' :
* curresult + + = ' : ' ;
break ;
case ' 4 ' :
* curresult + + = ' . ' ;
break ;
case ' 5 ' :
* curresult + + = ' ' ;
break ;
case ' 6 ' :
* curresult + + = ' \\ ' ;
* curresult + + = ' n ' ;
break ;
case ' 8 ' :
* curresult + + = ' \' ' ;
break ;
case ' 9 ' :
* curresult + + = ' - ' ;
break ;
/* any other arbitrary ASCII value can
be stored by prefixing it with ? $
*/
case ' $ ' :
state = DEMANGLE_STATE_DOLLAR_1 ;
}
break ;
case DEMANGLE_STATE_DOLLAR_1 :
/* first digit of ?$ notation. All digits
are hex , represented starting with the
capital leter ' A ' such that ' A ' means 0x0 ,
' B ' means 0x1 , ' K ' means 0xA
*/
hex_state = ( * curchar - ' A ' ) * 0x10 ;
state = DEMANGLE_STATE_DOLLAR_2 ;
break ;
case DEMANGLE_STATE_DOLLAR_2 :
/* same mechanism as above */
hex_state + = ( * curchar - ' A ' ) ;
if ( hex_state ) {
2003-01-24 03:27:17 +03:00
* curresult + + = DEMANGLE_SAFE_CHAR ( hex_state ) ;
2003-01-09 11:03:23 +03:00
have_null_char = 0 ;
}
else {
have_null_char = 1 ;
}
state = DEMANGLE_STATE_NORMAL ;
break ;
case DEMANGLE_STATE_STOP :
break ;
}
curchar + + ;
}
/* add the appropriate termination depending
if we completed the string or not */
if ( ! have_null_char )
strcpy ( curresult , " ... \" " ) ;
else
strcpy ( curresult , " \" " ) ;
} else {
retval = strdup ( demangleBuf ) ;
}
2002-12-15 01:53:31 +03:00
}
else
{
/*
* * fall back to normal .
*/
retval = strdup ( inSymbol ) ;
}
}
else if ( ' _ ' = = inSymbol [ 0 ] )
{
retval = strdup ( inSymbol + 1 ) ;
}
else
{
retval = strdup ( inSymbol ) ;
}
/*
* * May need to rewrite the symbol if an import .
*/
if ( NULL ! = retval & & isImport )
{
const char importPrefix [ ] = " __declspec(dllimport) " ;
char importBuf [ 0x200 ] ;
int printRes = 0 ;
printRes = _snprintf ( importBuf , sizeof ( importBuf ) , " %s%s " , importPrefix , retval ) ;
free ( retval ) ;
retval = NULL ;
if ( printRes > 0 )
{
retval = strdup ( importBuf ) ;
}
}
}
# else /* F_DEMANGLE */
2002-12-15 02:47:19 +03:00
retval = strdup ( inSymbol ) ;
2002-12-15 01:53:31 +03:00
# endif /* F_DEMANGLE */
return retval ;
}
2002-10-04 06:33:15 +04:00
int readmap ( Options * inOptions , MSMap_Module * inModule )
/*
* * Read the input line by line , adding it to the module .
*/
{
int retval = 0 ;
char lineBuffer [ 0x400 ] ;
char * current = NULL ;
MSMap_ReadState fsm ;
int len = 0 ;
int forceContinue = 0 ;
memset ( & fsm , 0 , sizeof ( fsm ) ) ;
/*
* * Read the map file line by line .
* * We keep a simple state machine to determine what we ' re looking at .
*/
while ( 0 = = retval & & NULL ! = fgets ( lineBuffer , sizeof ( lineBuffer ) , inOptions - > mInput ) )
{
if ( forceContinue )
{
/*
* * Used to skip anticipated blank lines .
*/
forceContinue - - ;
continue ;
}
current = skipWhite ( lineBuffer ) ;
trimWhite ( current ) ;
len = strlen ( current ) ;
if ( fsm . mHasModule )
{
if ( fsm . mHasTimestamp )
{
if ( fsm . mHasPreferredLoadAddress )
{
if ( fsm . mHasSegmentData )
{
if ( fsm . mHasPublicSymbolData )
{
if ( fsm . mHasEntryPoint )
{
if ( fsm . mFoundStaticSymbols )
{
/*
* * A blank line means we ' ve reached the end of all static symbols .
*/
if ( len )
{
/*
* * We ' re adding a new symbol .
* * Make sure we have room for it .
*/
if ( inModule - > mSymbolCapacity = = inModule - > mSymbolCount )
{
void * moved = NULL ;
moved = realloc ( inModule - > mSymbols , sizeof ( MSMap_Symbol ) * ( inModule - > mSymbolCapacity + MSMAP_SYMBOL_GROWBY ) ) ;
if ( NULL ! = moved )
{
inModule - > mSymbolCapacity + = MSMAP_SYMBOL_GROWBY ;
inModule - > mSymbols = ( MSMap_Symbol * ) moved ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to grow symbols. " ) ;
}
}
if ( 0 = = retval & & inModule - > mSymbolCapacity > inModule - > mSymbolCount )
{
MSMap_Symbol * theSymbol = NULL ;
unsigned index = 0 ;
int scanRes = 0 ;
char symbolBuf [ 0x200 ] ;
index = inModule - > mSymbolCount ;
inModule - > mSymbolCount + + ;
theSymbol = ( inModule - > mSymbols + index ) ;
memset ( theSymbol , 0 , sizeof ( MSMap_Symbol ) ) ;
theSymbol - > mScope = STATIC ;
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " %x:%x %s %x " , ( unsigned * ) & ( theSymbol - > mPrefix ) , ( unsigned * ) & ( theSymbol - > mOffset ) , symbolBuf , ( unsigned * ) & ( theSymbol - > mRVABase ) ) ;
2002-10-04 06:33:15 +04:00
if ( 4 = = scanRes )
{
2002-12-15 01:53:31 +03:00
theSymbol - > mSymbol = symdup ( symbolBuf ) ;
if ( 0 = = retval )
2002-10-04 06:33:15 +04:00
{
2002-12-15 01:53:31 +03:00
if ( NULL ! = theSymbol - > mSymbol )
{
char * last = lastWord ( current ) ;
theSymbol - > mObject = strdup ( last ) ;
if ( NULL = = theSymbol - > mObject )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , last , " Unable to copy object name. " ) ;
}
}
else
2002-10-04 06:33:15 +04:00
{
retval = __LINE__ ;
2002-12-15 01:53:31 +03:00
ERROR_REPORT ( retval , symbolBuf , " Unable to copy symbol name. " ) ;
2002-10-04 06:33:15 +04:00
}
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to scan static symbols. " ) ;
}
}
}
else
{
/*
* * All done .
*/
break ;
}
}
else
{
/*
* * Static symbols are optional .
* * If no static symbols we ' re done .
* * Otherwise , set the flag such that it will work more .
*/
if ( 0 = = strcmp ( current , " Static symbols " ) )
{
fsm . mFoundStaticSymbols = __LINE__ ;
forceContinue = 1 ;
}
else
{
/*
* * All done .
*/
break ;
}
}
}
else
{
int scanRes = 0 ;
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " entry point at %x:%x " , ( unsigned * ) & ( inModule - > mEntryPrefix ) , ( unsigned * ) & ( inModule - > mEntryOffset ) ) ;
2002-10-04 06:33:15 +04:00
if ( 2 = = scanRes )
{
fsm . mHasEntryPoint = __LINE__ ;
forceContinue = 1 ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current , " Unable to obtain entry point. " ) ;
}
}
}
else
{
/*
* * Skip the N lines of public symbol data ( column headers ) .
*/
if ( 2 < = fsm . mHasPublicSymbolDataSkippedLines )
{
/*
* * A blank line indicates end of public symbols .
*/
if ( len )
{
/*
* * We ' re adding a new symbol .
* * Make sure we have room for it .
*/
if ( inModule - > mSymbolCapacity = = inModule - > mSymbolCount )
{
void * moved = NULL ;
moved = realloc ( inModule - > mSymbols , sizeof ( MSMap_Symbol ) * ( inModule - > mSymbolCapacity + MSMAP_SYMBOL_GROWBY ) ) ;
if ( NULL ! = moved )
{
inModule - > mSymbolCapacity + = MSMAP_SYMBOL_GROWBY ;
inModule - > mSymbols = ( MSMap_Symbol * ) moved ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to grow symbols. " ) ;
}
}
if ( 0 = = retval & & inModule - > mSymbolCapacity > inModule - > mSymbolCount )
{
MSMap_Symbol * theSymbol = NULL ;
unsigned index = 0 ;
int scanRes = 0 ;
char symbolBuf [ 0x200 ] ;
index = inModule - > mSymbolCount ;
inModule - > mSymbolCount + + ;
theSymbol = ( inModule - > mSymbols + index ) ;
memset ( theSymbol , 0 , sizeof ( MSMap_Symbol ) ) ;
theSymbol - > mScope = PUBLIC ;
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " %x:%x %s %x " , ( unsigned * ) & ( theSymbol - > mPrefix ) , ( unsigned * ) & ( theSymbol - > mOffset ) , symbolBuf , ( unsigned * ) & ( theSymbol - > mRVABase ) ) ;
2002-10-04 06:33:15 +04:00
if ( 4 = = scanRes )
{
2002-12-15 01:53:31 +03:00
theSymbol - > mSymbol = symdup ( symbolBuf ) ;
2002-10-04 06:33:15 +04:00
if ( NULL ! = theSymbol - > mSymbol )
{
char * last = lastWord ( current ) ;
theSymbol - > mObject = strdup ( last ) ;
2003-01-22 17:06:15 +03:00
if ( NULL ! = theSymbol - > mObject )
{
/*
* * Finally , attempt to lookup the actual size of the symbol
* * if there is a symbol DB available .
*/
2003-01-23 18:13:24 +03:00
retval = fillSymbolSizeFromDB ( inOptions , inModule , theSymbol , symbolBuf ) ;
2003-01-22 17:06:15 +03:00
}
else
2002-10-04 06:33:15 +04:00
{
retval = __LINE__ ;
ERROR_REPORT ( retval , last , " Unable to copy object name. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , symbolBuf , " Unable to copy symbol name. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to scan public symbols. " ) ;
}
}
}
else
{
fsm . mHasPublicSymbolData = __LINE__ ;
}
}
else
{
fsm . mHasPublicSymbolDataSkippedLines + + ;
}
}
}
else
{
/*
* * Skip the first line of segment data ( column headers ) .
* * Mark that we ' ve begun grabbing segement data .
*/
if ( fsm . mSegmentDataSkippedLine )
{
/*
* * A blank line means end of the segment data .
*/
if ( len )
{
/*
* * We ' re adding a new segment .
* * Make sure we have room for it .
*/
if ( inModule - > mSegmentCapacity = = inModule - > mSegmentCount )
{
void * moved = NULL ;
moved = realloc ( inModule - > mSegments , sizeof ( MSMap_Segment ) * ( inModule - > mSegmentCapacity + MSMAP_SEGMENT_GROWBY ) ) ;
if ( NULL ! = moved )
{
inModule - > mSegmentCapacity + = MSMAP_SEGMENT_GROWBY ;
inModule - > mSegments = ( MSMap_Segment * ) moved ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to grow segments. " ) ;
}
}
if ( 0 = = retval & & inModule - > mSegmentCapacity > inModule - > mSegmentCount )
{
MSMap_Segment * theSegment = NULL ;
unsigned index = 0 ;
char classBuf [ 0x10 ] ;
char nameBuf [ 0x20 ] ;
int scanRes = 0 ;
index = inModule - > mSegmentCount ;
inModule - > mSegmentCount + + ;
theSegment = ( inModule - > mSegments + index ) ;
memset ( theSegment , 0 , sizeof ( MSMap_Segment ) ) ;
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " %x:%x %xH %s %s " , ( unsigned * ) & ( theSegment - > mPrefix ) , ( unsigned * ) & ( theSegment - > mOffset ) , ( unsigned * ) & ( theSegment - > mLength ) , nameBuf , classBuf ) ;
2002-10-04 06:33:15 +04:00
if ( 5 = = scanRes )
{
if ( ' . ' = = nameBuf [ 0 ] )
{
theSegment - > mSegment = strdup ( & nameBuf [ 1 ] ) ;
}
else
{
theSegment - > mSegment = strdup ( nameBuf ) ;
}
if ( NULL ! = theSegment - > mSegment )
{
if ( 0 = = strcmp ( " DATA " , classBuf ) )
{
theSegment - > mClass = DATA ;
}
else if ( 0 = = strcmp ( " CODE " , classBuf ) )
{
theSegment - > mClass = CODE ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , classBuf , " Unrecognized segment class. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , nameBuf , " Unable to copy segment name. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inModule - > mModule , " Unable to scan segments. " ) ;
}
}
}
else
{
fsm . mHasSegmentData = __LINE__ ;
}
}
else
{
fsm . mSegmentDataSkippedLine = __LINE__ ;
}
}
}
else
{
int scanRes = 0 ;
/*
* * The PLA has a particular format .
*/
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " Preferred load address is %x " , ( unsigned * ) & ( inModule - > mPreferredLoadAddress ) ) ;
2002-10-04 06:33:15 +04:00
if ( 1 = = scanRes )
{
fsm . mHasPreferredLoadAddress = __LINE__ ;
forceContinue = 1 ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current , " Unable to obtain preferred load address. " ) ;
}
}
}
else
{
int scanRes = 0 ;
/*
* * The timestamp has a particular format .
*/
2002-10-11 04:50:08 +04:00
scanRes = sscanf ( current , " Timestamp is %x " , ( unsigned * ) & ( inModule - > mTimestamp ) ) ;
2002-10-04 06:33:15 +04:00
if ( 1 = = scanRes )
{
fsm . mHasTimestamp = __LINE__ ;
forceContinue = 1 ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current , " Unable to obtain timestamp. " ) ;
}
}
}
else
{
/*
* * The module is on a line by itself .
*/
inModule - > mModule = strdup ( current ) ;
if ( NULL ! = inModule - > mModule )
{
fsm . mHasModule = __LINE__ ;
forceContinue = 1 ;
2002-11-16 01:48:39 +03:00
if ( 0 ! = inOptions - > mMatchModuleCount )
{
unsigned matchLoop = 0 ;
/*
* * If this module name doesn ' t match , then bail .
* * Compare in a case sensitive manner , exact match only .
*/
for ( matchLoop = 0 ; matchLoop < inOptions - > mMatchModuleCount ; matchLoop + + )
{
if ( 0 = = strcmp ( inModule - > mModule , inOptions - > mMatchModules [ matchLoop ] ) )
{
break ;
}
}
if ( matchLoop = = inOptions - > mMatchModuleCount )
{
/*
* * A match did not occur , bail out of read loop .
* * No error , however .
*/
break ;
}
}
2002-10-04 06:33:15 +04:00
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current , " Unable to obtain module. " ) ;
}
}
}
if ( 0 = = retval & & 0 ! = ferror ( inOptions - > mInput ) )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inOptions - > mInputName , " Unable to read file. " ) ;
}
return retval ;
}
static int qsortRVABase ( const void * in1 , const void * in2 )
/*
* * qsort callback to sort the symbols by their RVABase .
*/
{
MSMap_Symbol * sym1 = ( MSMap_Symbol * ) in1 ;
MSMap_Symbol * sym2 = ( MSMap_Symbol * ) in2 ;
int retval = 0 ;
if ( sym1 - > mRVABase < sym2 - > mRVABase )
{
retval = - 1 ;
}
else if ( sym1 - > mRVABase > sym2 - > mRVABase )
{
retval = 1 ;
}
return retval ;
}
2003-01-23 18:13:24 +03:00
static int tsvout ( Options * inOptions , unsigned inSize , MSMap_SegmentClass inClass , MSMap_SymbolScope inScope , const char * inModule , const char * inSegment , const char * inObject , const char * inSymbol )
2002-10-04 06:33:15 +04:00
/*
* * Output a line of map information seperated by tabs .
* * Some items ( const char * ) , if not present , will receive a default value .
*/
{
int retval = 0 ;
/*
* * No need to output on no size .
* * This can happen with zero sized segments ,
* * or an imported symbol which has multiple names ( one will count ) .
*/
if ( 0 ! = inSize )
{
char objectBuf [ 0x100 ] ;
const char * symScope = NULL ;
const char * segClass = NULL ;
const char * undefined = " UNDEF " ;
/*
* * Fill in unspecified values .
*/
if ( NULL = = inObject )
{
sprintf ( objectBuf , " %s:%s:%s " , undefined , inModule , inSegment ) ;
inObject = objectBuf ;
}
if ( NULL = = inSymbol )
{
inSymbol = inObject ;
}
/*
* * Convert some enumerations to text .
*/
switch ( inClass )
{
case CODE :
segClass = " CODE " ;
break ;
case DATA :
segClass = " DATA " ;
break ;
default :
retval = __LINE__ ;
ERROR_REPORT ( retval , " " , " Unable to determine class for output. " ) ;
break ;
}
switch ( inScope )
{
case PUBLIC :
symScope = " PUBLIC " ;
break ;
case STATIC :
symScope = " STATIC " ;
break ;
case UNDEFINED :
symScope = undefined ;
break ;
default :
retval = __LINE__ ;
ERROR_REPORT ( retval , " " , " Unable to determine scope for symbol. " ) ;
break ;
}
if ( 0 = = retval )
{
int printRes = 0 ;
printRes = fprintf ( inOptions - > mOutput ,
2003-01-23 18:13:24 +03:00
" %.8X \t %s \t %s \t %s \t %s \t %s \t %s \n " ,
2002-10-04 06:33:15 +04:00
inSize ,
segClass ,
symScope ,
inModule ,
inSegment ,
inObject ,
inSymbol
) ;
if ( 0 > printRes )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , inOptions - > mOutputName , " Unable to output tsv data. " ) ;
}
}
}
return retval ;
}
void cleanModule ( MSMap_Module * inModule )
{
unsigned loop = 0 ;
for ( loop = 0 ; loop < inModule - > mSymbolCount ; loop + + )
{
CLEANUP ( inModule - > mSymbols [ loop ] . mObject ) ;
CLEANUP ( inModule - > mSymbols [ loop ] . mSymbol ) ;
}
CLEANUP ( inModule - > mSymbols ) ;
for ( loop = 0 ; loop < inModule - > mSegmentCount ; loop + + )
{
CLEANUP ( inModule - > mSegments [ loop ] . mSegment ) ;
}
CLEANUP ( inModule - > mSegments ) ;
CLEANUP ( inModule - > mModule ) ;
memset ( inModule , 0 , sizeof ( MSMap_Module ) ) ;
}
int map2tsv ( Options * inOptions )
/*
* * Read all input .
* * Output tab seperated value data .
*/
{
int retval = 0 ;
MSMap_Module module ;
memset ( & module , 0 , sizeof ( module ) ) ;
/*
* * Read in the map file .
*/
retval = readmap ( inOptions , & module ) ;
if ( 0 = = retval )
{
unsigned symLoop = 0 ;
MSMap_Symbol * symbol = NULL ;
2003-01-23 18:13:24 +03:00
unsigned secLoop = 0 ;
MSMap_Segment * section = NULL ;
unsigned size = 0 ;
unsigned dbSize = 0 ;
unsigned offsetSize = 0 ;
unsigned endOffset = 0 ;
2002-10-04 06:33:15 +04:00
/*
* * Quick sort the symbols via RVABase .
*/
qsort ( module . mSymbols , module . mSymbolCount , sizeof ( MSMap_Symbol ) , qsortRVABase ) ;
/*
2003-01-23 18:13:24 +03:00
* * Go through all the symbols ( in order by sort ) .
* * Output their sizes .
2002-10-04 06:33:15 +04:00
*/
2003-01-23 18:13:24 +03:00
for ( symLoop = 0 ; 0 = = retval & & symLoop < module . mSymbolCount ; symLoop + + )
2002-10-04 06:33:15 +04:00
{
2003-01-23 18:13:24 +03:00
symbol = & module . mSymbols [ symLoop ] ;
section = getSymbolSection ( & module , symbol ) ;
2003-11-17 09:48:34 +03:00
if ( ! section )
continue ;
2002-10-04 06:33:15 +04:00
2003-01-23 18:13:24 +03:00
/*
* * Use the symbol DB size if available .
*/
dbSize = symbol - > mSymDBSize ;
2002-10-04 06:33:15 +04:00
2003-01-23 18:13:24 +03:00
/*
* * Guess using offsets .
* * Is there a next symbol available ? If so , it ' s start offset is the end of this symbol .
* * Otherwise , our section offset + length is the end of this symbol .
* *
* * The trick is , the DB size can not go beyond the offset size , for sanity .
*/
/*
* * Try next symbol , but only if in same section .
* * If still not , use the end of the segment .
* * This implies we were the last symbol in the segment .
*/
if ( ( symLoop + 1 ) < module . mSymbolCount )
{
MSMap_Symbol * nextSymbol = NULL ;
MSMap_Segment * nextSection = NULL ;
nextSymbol = & module . mSymbols [ symLoop + 1 ] ;
nextSection = getSymbolSection ( & module , nextSymbol ) ;
if ( section = = nextSection )
2002-10-04 06:33:15 +04:00
{
2003-01-23 18:13:24 +03:00
endOffset = nextSymbol - > mOffset ;
2002-10-04 06:33:15 +04:00
}
2003-01-23 18:13:24 +03:00
else
{
endOffset = section - > mOffset + section - > mLength ;
}
}
else
{
endOffset = section - > mOffset + section - > mLength ;
2002-10-04 06:33:15 +04:00
}
/*
2003-01-23 18:13:24 +03:00
* * Can now guess at size .
2002-10-04 06:33:15 +04:00
*/
2003-01-23 18:13:24 +03:00
offsetSize = endOffset - symbol - > mOffset ;
/*
* * Now , determine which size to use .
* * This is really a sanity check as well .
*/
size = offsetSize ;
if ( 0 ! = dbSize )
2002-10-04 06:33:15 +04:00
{
2003-01-23 18:13:24 +03:00
if ( dbSize < offsetSize )
2002-10-04 06:33:15 +04:00
{
2003-01-23 18:13:24 +03:00
size = dbSize ;
2002-10-04 06:33:15 +04:00
}
}
2003-01-23 18:13:24 +03:00
/*
* * Output the symbol with the size .
*/
retval = tsvout ( inOptions ,
size ,
section - > mClass ,
symbol - > mScope ,
module . mModule ,
section - > mSegment ,
symbol - > mObject ,
symbol - > mSymbol
) ;
/*
* * Make sure we mark this amount of space as used in the section .
*/
section - > mUsed + = size ;
}
/*
* * Go through the sections , and those whose length is longer than the
* * amount of space used , output dummy filler values .
*/
for ( secLoop = 0 ; 0 = = retval & & secLoop < module . mSegmentCount ; secLoop + + )
{
section = & module . mSegments [ secLoop ] ;
2003-11-17 09:48:34 +03:00
if ( section & & section - > mUsed < section - > mLength )
2003-01-23 18:13:24 +03:00
{
retval = tsvout ( inOptions ,
section - > mLength - section - > mUsed ,
section - > mClass ,
UNDEFINED ,
module . mModule ,
section - > mSegment ,
NULL ,
NULL
) ;
}
2002-10-04 06:33:15 +04:00
}
}
/*
* * Cleanup .
*/
cleanModule ( & module ) ;
return retval ;
}
int initOptions ( Options * outOptions , int inArgc , char * * inArgv )
/*
* * returns int 0 if successful .
*/
{
int retval = 0 ;
int loop = 0 ;
int switchLoop = 0 ;
int match = 0 ;
const int switchCount = sizeof ( gSwitches ) / sizeof ( gSwitches [ 0 ] ) ;
Switch * current = NULL ;
/*
* * Set any defaults .
*/
memset ( outOptions , 0 , sizeof ( Options ) ) ;
outOptions - > mProgramName = inArgv [ 0 ] ;
outOptions - > mInput = stdin ;
outOptions - > mInputName = strdup ( " stdin " ) ;
outOptions - > mOutput = stdout ;
outOptions - > mOutputName = strdup ( " stdout " ) ;
if ( NULL = = outOptions - > mOutputName | | NULL = = outOptions - > mInputName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , " stdin/stdout " , " Unable to strdup. " ) ;
}
/*
* * Go through and attempt to do the right thing .
*/
for ( loop = 1 ; loop < inArgc & & 0 = = retval ; loop + + )
{
match = 0 ;
current = NULL ;
for ( switchLoop = 0 ; switchLoop < switchCount & & 0 = = retval ; switchLoop + + )
{
if ( 0 = = strcmp ( gSwitches [ switchLoop ] - > mLongName , inArgv [ loop ] ) )
{
match = __LINE__ ;
}
else if ( 0 = = strcmp ( gSwitches [ switchLoop ] - > mShortName , inArgv [ loop ] ) )
{
match = __LINE__ ;
}
if ( match )
{
if ( gSwitches [ switchLoop ] - > mHasValue )
{
/*
* * Attempt to absorb next option to fullfill value .
*/
if ( loop + 1 < inArgc )
{
loop + + ;
current = gSwitches [ switchLoop ] ;
current - > mValue = inArgv [ loop ] ;
}
}
else
{
current = gSwitches [ switchLoop ] ;
}
break ;
}
}
if ( 0 = = match )
{
outOptions - > mHelp = __LINE__ ;
retval = __LINE__ ;
ERROR_REPORT ( retval , inArgv [ loop ] , " Unknown command line switch. " ) ;
}
else if ( NULL = = current )
{
outOptions - > mHelp = __LINE__ ;
retval = __LINE__ ;
ERROR_REPORT ( retval , inArgv [ loop ] , " Command line switch requires a value. " ) ;
}
else
{
/*
* * Do something based on address / swtich .
*/
if ( current = = & gInputSwitch )
{
CLEANUP ( outOptions - > mInputName ) ;
if ( NULL ! = outOptions - > mInput & & stdin ! = outOptions - > mInput )
{
fclose ( outOptions - > mInput ) ;
outOptions - > mInput = NULL ;
}
outOptions - > mInput = fopen ( current - > mValue , " r " ) ;
if ( NULL = = outOptions - > mInput )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to open input file. " ) ;
}
else
{
outOptions - > mInputName = strdup ( current - > mValue ) ;
if ( NULL = = outOptions - > mInputName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to strdup. " ) ;
}
}
}
else if ( current = = & gOutputSwitch )
{
CLEANUP ( outOptions - > mOutputName ) ;
if ( NULL ! = outOptions - > mOutput & & stdout ! = outOptions - > mOutput )
{
fclose ( outOptions - > mOutput ) ;
outOptions - > mOutput = NULL ;
}
outOptions - > mOutput = fopen ( current - > mValue , " a " ) ;
if ( NULL = = outOptions - > mOutput )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to open output file. " ) ;
}
else
{
outOptions - > mOutputName = strdup ( current - > mValue ) ;
if ( NULL = = outOptions - > mOutputName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to strdup. " ) ;
}
}
}
else if ( current = = & gHelpSwitch )
{
outOptions - > mHelp = __LINE__ ;
}
2002-11-16 01:48:39 +03:00
else if ( current = = & gMatchModuleSwitch )
{
void * moved = NULL ;
/*
* * Add the value to the list of allowed module names .
*/
moved = realloc ( outOptions - > mMatchModules , sizeof ( char * ) * ( outOptions - > mMatchModuleCount + 1 ) ) ;
if ( NULL ! = moved )
{
outOptions - > mMatchModules = ( char * * ) moved ;
outOptions - > mMatchModules [ outOptions - > mMatchModuleCount ] = strdup ( current - > mValue ) ;
if ( NULL ! = outOptions - > mMatchModules [ outOptions - > mMatchModuleCount ] )
{
outOptions - > mMatchModuleCount + + ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to duplicate string. " ) ;
}
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to allocate space for string. " ) ;
}
}
2003-01-22 17:06:15 +03:00
else if ( current = = & gSymDBSwitch )
{
CLEANUP ( outOptions - > mSymDBName ) ;
outOptions - > mSymDBName = strdup ( current - > mValue ) ;
if ( NULL = = outOptions - > mSymDBName )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mValue , " Unable to duplicate symbol db name. " ) ;
}
}
2003-01-23 18:13:24 +03:00
else if ( current = = & gBatchModeSwitch )
{
outOptions - > mBatchMode = __LINE__ ;
}
2002-10-04 06:33:15 +04:00
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , current - > mLongName , " No hanlder for command line switch. " ) ;
}
}
}
return retval ;
}
void cleanOptions ( Options * inOptions )
/*
2003-01-23 18:13:24 +03:00
* * Clean up any open handles , et . al .
2002-10-04 06:33:15 +04:00
*/
{
CLEANUP ( inOptions - > mInputName ) ;
if ( NULL ! = inOptions - > mInput & & stdin ! = inOptions - > mInput )
{
fclose ( inOptions - > mInput ) ;
}
CLEANUP ( inOptions - > mOutputName ) ;
if ( NULL ! = inOptions - > mOutput & & stdout ! = inOptions - > mOutput )
{
fclose ( inOptions - > mOutput ) ;
}
2002-11-16 01:48:39 +03:00
while ( 0 ! = inOptions - > mMatchModuleCount )
{
inOptions - > mMatchModuleCount - - ;
CLEANUP ( inOptions - > mMatchModules [ inOptions - > mMatchModuleCount ] ) ;
}
CLEANUP ( inOptions - > mMatchModules ) ;
2002-10-04 06:33:15 +04:00
2003-01-23 18:13:24 +03:00
cleanSymDB ( & inOptions - > mSymDB ) ;
2002-10-04 06:33:15 +04:00
memset ( inOptions , 0 , sizeof ( Options ) ) ;
}
void showHelp ( Options * inOptions )
/*
* * Show some simple help text on usage .
*/
{
int loop = 0 ;
const int switchCount = sizeof ( gSwitches ) / sizeof ( gSwitches [ 0 ] ) ;
const char * valueText = NULL ;
printf ( " usage: \t %s [arguments] \n " , inOptions - > mProgramName ) ;
printf ( " \n " ) ;
printf ( " arguments: \n " ) ;
for ( loop = 0 ; loop < switchCount ; loop + + )
{
if ( gSwitches [ loop ] - > mHasValue )
{
valueText = " <value> " ;
}
else
{
valueText = " " ;
}
printf ( " \t %s%s \n " , gSwitches [ loop ] - > mLongName , valueText ) ;
printf ( " \t %s%s " , gSwitches [ loop ] - > mShortName , valueText ) ;
printf ( DESC_NEWLINE " %s \n \n " , gSwitches [ loop ] - > mDescription ) ;
}
2002-10-17 05:06:06 +04:00
printf ( " This tool normalizes MS linker .map files for use by other tools. \n " ) ;
2002-10-04 06:33:15 +04:00
}
2003-01-23 18:13:24 +03:00
int batchMode ( Options * inOptions )
/*
* * Batch mode means that the input file is actually a list of map files .
* * We simply swap out our input file names while we do this .
*/
{
int retval = 0 ;
char lineBuf [ 0x400 ] ;
FILE * realInput = NULL ;
char * realInputName = NULL ;
FILE * mapFile = NULL ;
int finalRes = 0 ;
realInput = inOptions - > mInput ;
realInputName = inOptions - > mInputName ;
while ( 0 = = retval & & NULL ! = fgets ( lineBuf , sizeof ( lineBuf ) , realInput ) )
{
trimWhite ( lineBuf ) ;
/*
* * Skip / allow blank lines .
*/
if ( ' \0 ' = = lineBuf [ 0 ] )
{
continue ;
}
/*
* * Override what we believe to be the input for this line .
*/
inOptions - > mInputName = lineBuf ;
inOptions - > mInput = fopen ( lineBuf , " r " ) ;
if ( NULL ! = inOptions - > mInput )
{
int mapRes = 0 ;
/*
* * Do it .
*/
mapRes = map2tsv ( inOptions ) ;
/*
* * We report the first error that we encounter , but we continue .
* * This is batch mode after all .
*/
if ( 0 = = finalRes )
{
finalRes = mapRes ;
}
/*
* * Close the input file .
*/
fclose ( inOptions - > mInput ) ;
}
else
{
retval = __LINE__ ;
ERROR_REPORT ( retval , lineBuf , " Unable to open map file. " ) ;
break ;
}
}
if ( 0 = = retval & & 0 ! = ferror ( realInput ) )
{
retval = __LINE__ ;
ERROR_REPORT ( retval , realInputName , " Unable to read file. " ) ;
}
/*
* * Restore what we ' ve swapped .
*/
inOptions - > mInput = realInput ;
inOptions - > mInputName = realInputName ;
/*
* * Report first map file error if there were no other operational
* * problems .
*/
if ( 0 = = retval )
{
retval = finalRes ;
}
return retval ;
}
2002-10-04 06:33:15 +04:00
int main ( int inArgc , char * * inArgv )
{
int retval = 0 ;
Options options ;
retval = initOptions ( & options , inArgc , inArgv ) ;
if ( options . mHelp )
{
showHelp ( & options ) ;
}
else if ( 0 = = retval )
{
2003-01-23 18:13:24 +03:00
if ( options . mBatchMode )
{
retval = batchMode ( & options ) ;
}
else
{
retval = map2tsv ( & options ) ;
}
2002-10-04 06:33:15 +04:00
}
cleanOptions ( & options ) ;
return retval ;
}